Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

php-cs-fixer 3.1MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913989149891598916989179891898919989209892198922989239892498925989269892798928989299893098931989329893398934989359893698937989389893998940989419894298943989449894598946989479894898949989509895198952989539895498955989569895798958989599896098961989629896398964989659896698967989689896998970989719897298973989749897598976989779897898979989809898198982989839898498985989869898798988989899899098991989929899398994989959899698997989989899999000990019900299003990049900599006990079900899009990109901199012990139901499015990169901799018990199902099021990229902399024990259902699027990289902999030990319903299033990349903599036990379903899039990409904199042990439904499045990469904799048990499905099051990529905399054990559905699057990589905999060990619906299063990649906599066990679906899069990709907199072990739907499075990769907799078990799908099081990829908399084990859908699087990889908999090990919909299093990949909599096990979909899099991009910199102991039910499105991069910799108991099911099111991129911399114991159911699117991189911999120991219912299123991249912599126991279912899129991309913199132991339913499135991369913799138991399914099141991429914399144991459914699147991489914999150991519915299153991549915599156991579915899159991609916199162991639916499165991669916799168991699917099171991729917399174991759917699177991789917999180991819918299183991849918599186991879918899189991909919199192991939919499195991969919799198991999920099201992029920399204992059920699207992089920999210992119921299213992149921599216992179921899219992209922199222992239922499225992269922799228992299923099231992329923399234992359923699237992389923999240992419924299243992449924599246992479924899249992509925199252992539925499255992569925799258992599926099261992629926399264992659926699267992689926999270992719927299273992749927599276992779927899279992809928199282992839928499285992869928799288992899929099291992929929399294992959929699297992989929999300993019930299303993049930599306993079930899309993109931199312993139931499315993169931799318993199932099321993229932399324993259932699327993289932999330993319933299333993349933599336993379933899339993409934199342993439934499345993469934799348993499935099351993529935399354993559935699357993589935999360993619936299363993649936599366993679936899369993709937199372993739937499375993769937799378993799938099381993829938399384993859938699387993889938999390993919939299393993949939599396993979939899399994009940199402994039940499405994069940799408994099941099411994129941399414994159941699417994189941999420994219942299423994249942599426994279942899429994309943199432994339943499435994369943799438994399944099441994429944399444994459944699447994489944999450994519945299453994549945599456994579945899459994609946199462994639946499465994669946799468994699947099471994729947399474994759947699477994789947999480994819948299483994849948599486994879948899489994909949199492994939949499495994969949799498994999950099501995029950399504995059950699507995089950999510995119951299513995149951599516995179951899519995209952199522995239952499525995269952799528995299953099531995329953399534995359953699537995389953999540995419954299543995449954599546995479954899549995509955199552995539955499555995569955799558995599956099561995629956399564995659956699567995689956999570995719957299573995749957599576995779957899579995809958199582995839958499585995869958799588995899959099591995929959399594995959959699597995989959999600996019960299603996049960599606996079960899609996109961199612996139961499615996169961799618996199962099621996229962399624996259962699627996289962999630996319963299633996349963599636996379963899639996409964199642996439964499645996469964799648996499965099651996529965399654996559965699657996589965999660996619966299663996649966599666996679966899669996709967199672996739967499675996769967799678996799968099681996829968399684996859968699687996889968999690996919969299693996949969599696996979969899699997009970199702997039970499705997069970799708997099971099711997129971399714997159971699717997189971999720997219972299723997249972599726997279972899729997309973199732997339973499735997369973799738997399974099741997429974399744997459974699747997489974999750997519975299753997549975599756997579975899759997609976199762997639976499765997669976799768997699977099771997729977399774997759977699777997789977999780997819978299783997849978599786997879978899789997909979199792997939979499795997969979799798997999980099801998029980399804998059980699807998089980999810998119981299813998149981599816998179981899819998209982199822998239982499825998269982799828998299983099831998329983399834998359983699837998389983999840998419984299843998449984599846998479984899849998509985199852998539985499855998569985799858998599986099861998629986399864998659986699867998689986999870998719987299873998749987599876998779987899879998809988199882998839988499885998869988799888998899989099891998929989399894998959989699897998989989999900999019990299903999049990599906999079990899909999109991199912999139991499915999169991799918999199992099921999229992399924999259992699927999289992999930999319993299933999349993599936999379993899939999409994199942999439994499945999469994799948999499995099951999529995399954999559995699957999589995999960999619996299963999649996599966999679996899969999709997199972999739997499975999769997799978999799998099981999829998399984999859998699987999889998999990999919999299993999949999599996999979999899999100000100001100002100003100004100005100006100007100008100009100010100011100012100013100014100015100016100017100018100019100020100021100022100023100024100025100026100027100028100029100030100031100032100033100034100035100036100037100038100039100040100041100042100043100044100045100046100047100048100049100050100051100052100053100054100055100056100057100058100059100060100061100062100063100064100065100066100067100068100069100070100071100072100073100074100075100076100077100078100079100080100081100082100083100084100085100086100087100088100089100090100091100092100093100094100095100096100097100098100099100100100101100102100103100104100105100106100107100108100109100110100111100112100113100114100115100116100117100118100119100120100121100122100123100124100125100126100127100128100129100130100131100132100133100134100135100136100137100138100139100140100141100142100143100144100145100146100147100148100149100150100151100152100153100154100155100156100157100158100159100160100161100162100163100164100165100166100167100168100169100170100171100172100173100174100175100176100177100178100179100180100181100182100183100184100185100186100187100188100189100190100191100192100193100194100195100196100197100198100199100200100201100202100203100204100205100206100207100208100209100210100211100212100213100214100215100216100217100218100219100220100221100222100223100224100225100226100227100228100229100230100231100232100233100234100235100236100237100238100239100240100241100242100243100244100245100246100247100248100249100250100251100252100253100254100255100256100257100258100259100260100261100262100263100264100265100266100267100268100269100270100271100272100273100274100275100276100277100278100279100280100281100282100283100284100285100286100287100288100289100290100291100292100293100294100295100296100297100298100299100300100301100302100303100304100305100306100307100308100309100310100311100312100313100314100315100316100317100318100319100320100321100322100323100324100325100326100327100328100329100330100331100332100333100334100335100336100337100338100339100340100341100342100343100344100345100346100347100348100349100350100351100352100353100354100355100356100357100358100359100360100361100362100363100364100365100366100367100368100369100370100371100372100373100374100375100376100377100378100379100380100381100382100383100384100385100386100387100388100389100390100391100392100393100394100395100396100397100398100399100400100401100402100403100404100405100406100407100408100409100410100411100412100413100414100415100416100417100418100419100420100421100422100423100424100425100426100427100428100429100430100431100432100433100434100435100436100437100438100439100440100441100442100443100444100445100446100447100448100449100450100451100452100453100454100455100456100457100458100459100460100461100462100463100464100465100466100467100468100469100470100471100472100473100474100475100476100477100478100479100480100481100482100483100484100485100486100487100488100489100490100491100492100493100494100495100496100497100498100499100500100501100502100503100504100505100506100507100508100509100510100511100512100513100514100515100516100517100518100519100520100521100522100523100524100525100526100527100528100529100530100531100532100533100534100535100536100537100538100539100540100541100542100543100544100545100546100547100548100549100550100551100552100553100554100555100556100557100558100559100560100561100562100563100564100565100566100567100568100569100570100571100572100573100574100575100576100577100578100579100580100581100582100583100584100585100586100587100588100589100590100591100592100593100594100595100596100597100598100599100600100601100602100603100604100605100606100607100608100609100610100611100612100613100614100615100616100617100618100619100620100621100622100623100624100625100626100627100628100629100630100631100632100633100634100635100636100637100638100639100640100641100642100643100644100645100646100647100648100649100650100651100652100653100654100655100656100657100658100659100660100661100662100663100664100665100666100667100668100669100670100671100672100673100674100675100676100677100678100679100680100681100682100683100684100685100686100687100688100689100690100691100692100693100694100695100696100697100698100699100700100701100702100703100704100705100706100707100708100709100710100711100712100713100714100715100716100717100718100719100720100721100722100723100724100725100726100727100728100729100730100731100732100733100734100735100736100737100738100739100740100741100742100743100744100745100746100747100748100749100750100751100752100753100754100755100756100757100758100759100760100761100762100763100764100765100766100767100768100769100770100771100772100773100774100775100776100777100778100779100780100781100782100783100784100785100786100787100788100789100790100791100792100793100794100795100796100797100798100799100800100801100802100803100804100805100806100807100808100809100810100811100812100813100814100815100816100817100818100819100820100821100822100823100824100825100826100827100828100829100830100831100832100833100834100835100836100837100838100839100840100841100842100843100844100845100846100847100848100849100850100851100852100853100854100855100856100857100858100859100860100861100862100863100864100865100866100867100868100869100870100871100872100873100874100875100876100877100878100879100880100881100882100883100884100885100886100887100888100889100890100891100892100893100894100895100896100897100898100899100900100901100902100903100904100905100906100907100908100909100910100911100912100913100914100915100916100917100918100919100920100921100922100923100924100925100926100927100928100929100930100931100932100933100934100935100936100937100938100939100940100941100942100943100944100945100946100947100948100949100950100951100952100953100954100955100956100957100958100959100960100961100962100963100964100965100966100967100968100969100970100971100972100973100974100975100976100977100978100979100980100981100982100983100984100985100986100987100988100989100990100991100992100993100994100995100996100997100998100999101000101001101002101003101004101005101006101007101008101009101010101011101012101013101014101015101016101017101018101019101020101021101022101023101024101025101026101027101028101029101030101031101032101033101034101035101036101037101038101039101040101041101042101043101044101045101046101047101048101049101050101051101052101053101054101055101056101057101058101059101060101061101062101063101064101065101066101067101068101069101070101071101072101073101074101075101076101077101078101079101080101081101082101083101084101085101086101087101088101089101090101091101092101093101094101095101096101097101098101099101100101101101102101103101104101105101106101107101108101109101110101111101112101113101114101115101116101117101118101119101120101121101122101123101124101125101126101127101128101129101130101131101132101133101134101135101136101137101138101139101140101141101142101143101144101145101146101147101148101149101150101151101152101153101154101155101156101157101158101159101160101161101162101163101164101165101166101167101168101169101170101171101172101173101174101175101176101177101178101179101180101181101182101183101184101185101186101187101188101189101190101191101192101193101194101195101196101197101198101199101200101201101202101203101204101205101206101207101208101209101210101211101212101213101214101215101216101217101218101219101220101221101222101223101224101225101226101227101228101229101230101231101232101233101234101235101236101237101238101239101240101241101242101243101244101245101246101247101248101249101250101251101252101253101254101255101256101257101258101259101260101261101262101263101264101265101266101267101268101269101270101271101272101273101274101275101276101277101278101279101280101281101282101283101284101285101286101287101288101289101290101291101292101293101294101295101296101297101298101299101300101301101302101303101304101305101306101307101308101309101310101311101312101313101314101315101316101317101318101319101320101321101322101323101324101325101326101327101328101329101330101331101332101333101334101335101336101337101338101339101340101341101342101343101344101345101346101347101348101349101350101351101352101353101354101355101356101357101358101359101360101361101362101363101364101365101366101367101368101369101370101371101372101373101374101375101376101377101378101379101380101381101382101383101384101385101386101387101388101389101390101391101392101393101394101395101396101397101398101399101400101401101402101403101404101405101406101407101408101409101410101411101412101413101414101415101416101417101418101419101420101421101422101423101424101425101426101427101428101429101430101431101432101433101434101435101436101437101438101439101440101441101442101443101444101445101446101447101448101449101450101451101452101453101454101455101456101457101458101459101460101461101462101463101464101465101466101467101468101469101470101471101472101473101474101475101476101477101478101479101480101481101482101483101484101485101486101487101488101489101490101491101492101493101494101495101496101497101498101499101500101501101502101503101504101505101506101507101508101509101510101511101512101513101514101515101516101517101518101519101520101521101522101523101524101525101526101527101528101529101530101531101532101533101534101535101536101537101538101539101540101541101542101543101544101545101546101547101548101549101550101551101552101553101554101555101556101557101558101559101560101561101562101563101564101565101566101567101568101569101570101571101572101573101574101575101576101577101578101579101580101581101582101583101584101585101586101587101588101589101590101591101592101593101594101595101596101597101598101599101600101601101602101603101604101605101606101607101608101609101610101611101612101613101614101615101616101617101618101619101620101621101622101623101624101625101626101627101628101629101630101631101632101633101634101635101636101637101638101639101640101641101642101643101644101645101646101647101648101649101650101651101652101653101654101655101656101657101658101659101660101661101662101663101664101665101666101667101668101669101670101671101672101673101674101675101676101677101678101679101680101681101682101683101684101685101686101687101688101689101690101691101692101693101694101695101696101697101698101699101700101701101702101703101704101705101706101707101708101709101710101711101712101713101714101715101716101717101718101719101720101721101722101723101724101725101726101727101728101729101730101731101732101733101734101735101736101737101738101739101740101741101742101743101744101745101746101747101748101749101750101751101752101753101754101755101756101757101758101759101760101761101762101763101764101765101766101767101768101769101770101771101772101773101774101775101776101777101778101779101780101781101782101783101784101785101786101787101788101789101790101791101792101793101794101795101796101797101798101799101800101801101802101803101804101805101806101807101808101809101810101811101812101813101814101815101816101817101818101819101820101821101822101823101824101825101826101827101828101829101830101831101832101833101834101835101836101837101838101839101840101841101842101843101844101845101846101847101848101849101850101851101852101853101854101855101856101857101858101859101860101861101862101863101864101865101866101867101868101869101870101871101872101873101874101875101876101877101878101879101880101881101882101883101884101885101886101887101888101889101890101891101892101893101894101895101896101897101898101899101900101901101902101903101904101905101906101907101908101909101910101911101912101913101914101915101916101917101918101919101920101921101922101923101924101925101926101927101928101929101930101931101932101933101934101935101936101937101938101939101940101941101942101943101944101945101946101947101948101949101950101951101952101953101954101955101956101957101958101959101960101961101962101963101964101965101966101967101968101969101970101971101972101973101974101975101976101977101978101979101980101981101982101983101984101985101986101987101988101989101990101991101992101993101994101995101996101997101998101999102000102001102002102003102004102005102006102007102008102009102010102011102012102013102014102015102016102017102018102019102020102021102022102023102024102025102026102027102028102029102030102031102032102033102034102035102036102037102038102039102040102041102042102043102044102045102046102047102048102049102050102051102052102053102054102055102056102057102058102059102060102061102062102063102064102065102066102067102068102069102070102071102072102073102074102075102076102077102078102079102080102081102082102083102084102085102086102087102088102089102090102091102092102093102094102095102096102097102098102099102100102101102102102103102104102105102106102107102108102109102110102111102112102113102114102115102116102117102118102119102120102121102122102123102124102125102126102127102128102129102130102131102132102133102134102135102136102137102138102139102140102141102142102143102144102145102146102147102148102149102150102151102152102153102154102155102156102157102158102159102160102161102162102163102164102165102166102167102168102169102170102171102172102173102174102175102176102177102178102179102180102181102182102183102184102185102186102187102188102189102190102191102192102193102194102195102196102197102198102199102200102201102202102203102204102205102206102207102208102209102210102211102212102213102214102215102216102217102218102219102220102221102222102223102224102225102226102227102228102229102230102231102232102233102234102235102236102237102238102239102240102241102242102243102244102245102246102247102248102249102250102251102252102253102254102255102256102257102258102259102260102261102262102263102264102265102266102267102268102269102270102271102272102273102274102275102276102277102278102279102280102281102282102283102284102285102286102287102288102289102290102291102292102293102294102295102296102297102298102299102300102301102302102303102304102305102306102307102308102309102310102311102312102313102314102315102316102317102318102319102320102321102322102323102324102325102326102327102328102329102330102331102332102333102334102335102336102337102338102339102340102341102342102343102344102345102346102347102348102349102350102351102352102353102354102355102356102357102358102359102360102361102362102363102364102365102366102367102368102369102370102371102372102373102374102375102376102377102378102379102380102381102382102383102384102385102386102387102388102389102390102391102392102393102394102395102396102397102398102399102400102401102402102403102404102405102406102407102408102409102410102411102412102413102414102415102416102417102418102419102420102421102422102423102424102425102426102427102428102429102430102431102432102433102434102435102436102437102438102439102440102441102442102443102444102445102446102447102448102449102450102451102452102453102454102455102456102457102458102459102460102461102462102463102464102465102466102467102468102469102470102471102472102473102474102475102476102477102478102479102480102481102482102483102484102485102486102487102488102489102490102491102492102493102494102495102496102497102498102499102500102501102502102503102504102505102506102507102508102509102510102511102512102513102514102515102516102517102518102519102520102521102522102523102524102525102526102527102528102529102530102531102532102533102534102535102536102537102538102539102540102541102542102543102544102545102546102547102548102549102550102551102552102553102554102555102556102557102558102559102560102561102562102563102564102565102566102567102568102569102570102571102572102573102574102575102576102577102578102579102580102581102582102583102584102585102586102587102588102589102590102591102592102593102594102595102596102597102598102599102600102601102602102603102604102605102606102607102608102609102610102611102612102613102614102615102616102617102618102619102620102621102622102623102624102625102626102627102628102629102630102631102632102633102634102635102636102637102638102639102640102641102642102643102644102645102646102647102648102649102650102651102652102653102654102655102656102657102658102659102660102661102662102663102664102665102666102667102668102669102670102671102672102673102674102675102676102677102678102679102680102681102682102683102684102685102686102687102688102689102690102691102692102693102694102695102696102697102698102699102700102701102702102703102704102705102706102707102708102709102710102711102712102713102714102715102716102717102718102719102720102721102722102723102724102725102726102727102728102729102730102731102732102733102734102735102736102737102738102739102740102741102742102743102744102745102746102747102748102749102750102751102752102753102754102755102756102757102758102759102760102761102762102763102764102765102766102767102768102769102770102771102772102773102774102775102776102777102778102779102780102781102782102783102784102785102786102787102788102789102790102791102792102793102794102795102796102797102798102799102800102801102802102803102804102805102806102807102808102809102810102811102812102813102814102815102816102817102818102819102820102821102822102823102824102825102826102827102828102829102830102831102832102833102834102835102836102837102838102839102840102841102842102843102844102845102846102847102848102849102850102851102852102853102854102855102856102857102858102859102860102861102862102863102864102865102866102867102868102869102870102871102872102873102874102875102876102877102878102879102880102881102882102883102884102885102886102887102888102889102890102891102892102893102894102895102896102897102898102899102900102901102902102903102904102905102906102907102908102909102910102911102912102913102914102915102916102917102918102919102920102921102922102923102924102925102926102927102928102929102930102931102932102933102934102935102936102937102938102939102940102941102942102943102944102945102946102947102948102949102950102951102952102953102954102955102956102957102958102959102960102961102962102963102964102965102966102967102968102969102970102971102972102973102974102975102976102977102978102979102980102981102982102983102984102985102986102987102988102989102990102991102992102993102994102995102996102997102998102999103000103001103002103003103004103005103006103007103008103009103010103011103012103013103014103015103016103017103018103019103020103021103022103023103024103025103026103027103028103029103030103031103032103033103034103035103036103037103038103039103040103041103042103043103044103045103046103047103048103049103050103051103052103053103054103055103056103057103058103059103060103061103062103063103064103065103066103067103068103069103070103071103072103073103074103075103076103077103078103079103080103081103082103083103084103085103086103087103088103089103090103091103092103093103094103095103096103097103098103099103100103101103102103103103104103105103106103107103108103109103110103111103112103113103114103115103116103117103118103119103120103121103122103123103124103125103126103127103128103129103130103131103132103133103134103135103136103137103138103139103140103141103142103143103144103145103146103147103148103149103150103151103152103153103154103155103156103157103158103159103160103161103162103163103164103165103166103167103168103169103170103171103172103173103174103175103176103177103178103179103180103181103182103183103184103185103186103187103188103189103190103191103192103193103194103195103196103197103198103199103200103201103202103203103204103205103206103207103208103209103210103211103212103213103214103215103216103217103218103219103220103221103222103223103224103225103226103227103228103229103230103231103232103233103234103235103236103237103238103239103240103241103242103243103244103245103246103247103248103249103250103251103252103253103254103255103256103257103258103259103260103261103262103263103264103265103266103267103268103269103270103271103272103273103274103275103276103277103278103279103280103281103282103283103284103285103286103287103288103289103290103291103292103293103294103295103296103297103298103299103300103301103302103303103304103305103306103307103308103309103310103311103312103313103314103315103316103317103318103319103320103321103322103323103324103325103326103327103328103329103330103331103332103333103334103335103336103337103338103339103340103341103342103343103344103345103346103347103348103349103350103351103352103353103354103355103356103357103358103359103360103361103362103363103364103365103366103367103368103369103370103371103372103373103374103375103376103377103378103379103380103381103382103383103384103385103386103387103388103389103390103391103392103393103394103395103396103397103398103399103400103401103402103403103404103405103406103407103408103409103410103411103412103413103414103415103416103417103418103419103420103421103422103423103424103425103426103427103428103429103430103431103432103433103434103435103436103437103438103439103440103441103442103443103444103445103446103447103448103449103450103451103452103453103454103455103456103457103458103459103460103461103462103463103464103465103466103467103468103469103470103471103472103473103474103475103476103477103478103479103480103481103482103483103484103485103486103487103488103489103490103491103492103493103494103495103496103497103498103499103500103501103502103503103504103505103506103507103508103509103510103511103512103513103514103515103516103517103518103519103520103521103522103523103524103525103526103527103528103529103530103531103532103533103534103535103536103537103538103539103540103541103542103543103544103545103546103547103548103549103550103551103552103553103554103555103556103557103558103559103560103561103562103563103564103565103566103567103568103569103570103571103572103573103574103575103576103577103578103579103580103581103582103583103584103585103586103587103588103589103590103591103592103593103594103595103596103597103598103599103600103601103602103603103604103605103606103607103608103609103610103611103612103613103614103615103616103617103618103619103620103621103622103623103624103625103626103627103628103629103630103631103632103633103634103635103636103637103638103639103640103641103642103643103644103645103646103647103648103649103650103651103652103653103654103655103656103657103658103659103660103661103662103663103664103665103666103667103668103669103670103671103672103673103674103675103676103677103678103679103680103681103682103683103684103685103686103687103688103689103690103691103692103693103694103695103696103697103698103699103700103701103702103703103704103705103706103707103708103709103710103711103712103713103714103715103716103717103718103719103720103721103722103723103724103725103726103727103728103729103730103731103732103733103734103735103736103737103738103739103740103741103742103743103744103745103746103747103748103749103750103751103752103753103754103755103756103757103758103759103760103761103762103763103764103765103766103767103768103769103770103771103772103773103774103775103776103777103778103779103780103781103782103783103784103785103786103787103788103789103790103791103792103793103794103795103796103797103798103799103800103801103802103803103804103805103806103807103808103809103810103811103812103813103814103815103816103817103818103819103820103821103822103823103824103825103826103827103828103829103830103831103832103833103834103835103836103837103838103839103840103841103842103843103844103845103846103847103848103849103850103851103852103853103854103855103856103857103858103859103860103861103862103863103864103865103866103867103868103869103870103871103872103873103874103875103876103877103878103879103880103881103882103883103884103885103886103887103888103889103890103891103892103893103894103895103896103897103898103899103900103901103902103903103904103905103906103907103908103909103910103911103912103913103914103915103916103917103918103919103920103921103922103923103924103925103926103927103928103929103930103931103932103933103934103935103936103937103938103939103940103941103942103943103944103945103946103947103948103949103950103951103952103953103954103955103956103957103958103959103960103961103962103963103964103965103966103967103968103969103970103971103972103973103974103975103976103977103978103979103980103981103982103983103984103985103986103987103988103989103990103991103992103993103994103995103996103997103998103999104000104001104002104003104004104005104006104007104008104009104010104011104012104013104014104015104016104017104018104019104020104021104022104023104024104025104026104027104028104029104030104031104032104033104034104035104036104037104038104039104040104041104042104043104044104045104046104047104048104049104050104051104052104053104054104055104056104057104058104059104060104061104062104063104064104065104066104067104068104069104070104071104072104073104074104075104076104077104078104079104080104081104082104083104084104085104086104087104088104089104090104091104092104093104094104095104096104097104098104099104100104101104102104103104104104105104106104107104108104109104110104111104112104113104114104115104116104117104118104119104120104121104122104123104124104125104126104127104128104129104130104131104132104133104134104135104136104137104138104139104140104141104142104143104144104145104146104147104148104149104150104151104152104153104154104155104156104157104158104159104160104161104162104163104164104165104166104167104168104169104170104171104172104173104174104175104176104177104178104179104180104181104182104183104184104185104186104187104188104189104190104191104192104193104194104195104196104197104198104199104200104201104202104203104204104205104206104207104208104209104210104211104212104213104214104215104216104217104218104219104220104221104222104223104224104225104226104227104228104229104230104231104232104233104234104235104236104237104238104239104240104241104242104243104244104245104246104247104248104249104250104251104252104253104254104255104256104257104258104259104260104261104262104263104264104265104266104267104268104269104270104271104272104273104274104275104276104277104278104279104280104281104282104283104284104285104286104287104288104289104290104291104292104293104294104295104296104297104298104299104300104301104302104303104304104305104306104307104308104309104310104311104312104313104314104315104316104317104318104319104320104321104322104323104324104325104326104327104328104329104330104331104332104333104334104335104336104337104338104339104340104341104342104343104344104345104346104347104348104349104350104351104352104353104354104355104356104357104358104359104360104361104362104363104364104365104366104367104368104369104370104371104372104373104374104375104376104377104378104379104380104381104382104383104384104385104386104387104388104389104390104391104392104393104394104395104396104397104398104399104400104401104402104403104404104405104406104407104408104409104410104411104412104413104414104415104416104417104418104419104420104421104422104423104424104425104426104427104428104429104430104431104432104433104434104435104436104437104438104439104440104441104442104443104444104445104446104447104448104449104450104451104452104453104454104455104456104457104458104459104460104461104462104463104464104465104466104467104468104469104470104471104472104473104474104475104476104477104478104479104480104481104482104483104484104485104486104487104488104489104490104491104492104493104494104495104496104497104498104499104500104501104502104503104504104505104506104507104508104509104510104511104512104513104514104515104516104517104518104519104520104521104522104523104524104525104526104527104528104529104530104531104532104533104534104535104536104537104538104539104540104541104542104543104544104545104546104547104548104549104550104551104552104553104554104555104556104557104558104559104560104561104562104563104564104565104566104567104568104569104570104571104572104573104574104575104576104577104578104579104580104581104582104583104584104585104586104587104588104589104590104591104592104593104594104595104596104597104598104599104600104601104602104603104604104605104606104607104608104609104610104611104612104613104614104615104616104617104618104619104620104621104622104623104624104625104626104627104628104629104630104631104632104633104634104635104636104637104638104639104640104641104642104643104644104645104646104647104648104649104650104651104652104653104654104655104656104657104658104659104660104661104662104663104664104665104666104667104668104669104670104671104672104673104674104675104676104677104678104679104680104681104682104683104684104685104686104687104688104689104690104691104692104693104694104695104696104697104698104699104700104701104702104703104704104705104706104707104708104709104710104711104712104713104714104715104716104717104718104719104720104721104722104723104724104725104726104727104728104729104730104731104732104733104734104735104736104737104738104739104740104741104742104743104744104745104746104747104748104749104750104751104752104753104754104755104756104757104758104759104760104761104762104763104764104765104766104767104768104769104770104771104772104773104774104775104776104777104778104779104780104781104782104783104784104785104786104787104788104789104790104791104792104793104794104795104796104797104798104799104800104801104802104803104804104805104806104807104808104809104810104811104812104813104814104815104816104817104818104819104820104821104822104823104824104825104826104827104828104829104830104831104832104833104834104835104836104837104838104839104840104841104842104843104844104845104846104847104848104849104850104851104852104853104854104855104856104857104858104859104860104861104862104863104864104865104866104867104868104869104870104871104872104873104874104875104876104877104878104879104880104881104882104883104884104885104886104887104888104889104890104891104892104893104894104895104896104897104898104899104900104901104902104903104904104905104906104907104908104909104910104911104912104913104914104915104916104917104918104919104920104921104922104923104924104925104926104927104928104929104930104931104932104933104934104935104936104937104938104939104940104941104942104943104944104945104946104947104948104949104950104951104952104953104954104955104956104957104958104959104960104961104962104963104964104965104966104967104968104969104970104971104972104973104974104975104976104977104978104979104980104981104982104983104984104985104986104987104988104989104990104991104992104993104994104995104996104997104998104999105000105001105002105003105004105005105006105007105008105009105010105011105012105013105014105015105016105017105018105019105020105021105022105023105024105025105026105027105028105029105030105031105032105033105034105035105036105037105038105039105040105041105042105043105044105045105046105047105048105049105050105051105052105053105054105055105056105057105058105059105060105061105062105063105064105065105066105067105068105069105070105071105072105073105074105075105076105077105078105079105080105081105082105083105084105085105086105087105088105089105090105091105092105093105094105095105096105097105098105099105100105101105102105103105104105105105106105107105108105109105110105111105112105113105114105115105116105117105118105119105120105121105122105123105124105125105126105127105128105129105130105131105132105133105134105135105136105137105138105139105140105141105142105143105144105145105146105147105148105149105150105151105152105153105154105155105156105157105158105159105160105161105162105163105164105165105166105167105168105169105170105171105172105173105174105175105176105177105178105179105180105181105182105183105184105185105186105187105188105189105190105191105192105193105194105195105196105197105198105199105200105201105202105203105204105205105206105207105208105209105210105211105212105213105214105215105216105217105218105219105220105221105222105223105224105225105226105227105228105229105230105231105232105233105234105235105236105237105238105239105240105241105242105243105244105245105246105247105248105249105250105251105252105253105254105255105256105257105258105259105260105261105262105263105264105265105266105267105268105269105270105271105272105273105274105275105276105277105278105279105280105281105282105283105284105285105286105287105288105289105290105291105292105293105294105295105296105297105298105299105300105301105302105303105304105305105306105307105308105309105310105311105312105313105314105315105316105317105318105319105320105321105322105323105324105325105326105327105328105329105330105331105332105333105334105335105336105337105338105339105340105341105342105343105344105345105346105347105348105349105350105351105352105353105354105355105356105357105358105359105360105361105362105363105364105365105366105367105368105369105370105371105372105373105374105375105376105377105378105379105380105381105382105383105384105385105386105387105388105389105390105391105392105393105394105395105396105397105398105399105400105401105402105403105404105405105406105407105408105409105410105411105412105413105414105415105416105417105418105419105420105421105422105423105424105425105426105427105428105429105430105431105432105433105434105435105436105437105438105439105440105441105442105443105444105445105446105447105448105449105450105451105452105453105454105455105456105457105458105459105460105461105462105463105464105465105466105467105468105469105470105471105472105473105474105475105476105477105478105479105480105481105482105483105484105485105486105487105488105489105490105491105492105493105494105495105496105497105498105499105500105501105502105503105504105505105506105507105508105509105510105511105512105513105514105515105516105517105518105519105520105521105522105523105524105525105526105527105528105529105530105531105532105533105534105535105536105537105538105539105540105541105542105543105544105545105546105547105548105549105550105551105552105553105554105555105556105557105558105559105560105561105562105563105564105565105566105567105568105569105570105571105572105573105574105575105576105577105578105579105580105581105582105583105584105585105586105587105588105589105590105591105592105593105594105595105596105597105598105599105600105601105602105603105604105605105606105607105608105609105610105611105612105613105614105615105616105617105618105619105620105621105622105623105624105625105626105627105628105629105630105631105632105633105634105635105636105637105638105639105640105641105642105643105644105645105646105647105648105649105650105651105652105653105654105655105656105657105658105659105660105661105662105663105664105665105666105667105668105669105670105671105672105673105674105675105676105677105678105679105680105681105682105683105684105685105686105687105688105689105690105691105692105693105694105695105696105697105698105699105700105701105702105703105704105705105706105707105708105709105710105711105712105713105714105715105716105717105718105719105720105721105722105723105724105725105726105727105728105729105730105731105732105733105734105735105736105737105738105739105740105741105742105743105744105745105746105747105748105749105750105751105752105753105754105755105756105757105758105759105760105761105762105763105764105765105766105767105768105769105770105771105772105773105774105775105776105777105778105779105780105781105782105783105784105785105786105787105788105789105790105791105792105793105794105795105796105797105798105799105800105801105802105803105804105805105806105807105808105809105810105811105812105813105814105815105816105817105818105819105820105821105822105823105824105825105826105827105828105829105830105831105832105833105834105835105836105837105838105839105840105841105842105843105844105845105846105847105848105849105850105851105852105853105854105855105856105857105858105859105860105861105862105863105864105865105866105867105868105869105870105871105872105873105874105875105876105877105878105879105880105881105882105883105884105885105886105887105888105889105890105891105892105893105894105895105896105897105898105899105900105901105902105903105904105905105906105907105908105909105910105911105912105913105914105915105916105917105918105919105920105921105922105923105924105925105926105927105928105929105930105931105932105933105934105935105936105937105938105939105940105941105942105943105944105945105946105947105948105949105950105951105952105953105954105955105956105957105958105959105960105961105962105963105964105965105966105967105968105969105970105971105972105973105974105975105976105977105978105979105980105981105982105983105984105985105986105987105988105989105990105991105992105993105994105995105996105997105998105999106000106001106002106003106004106005106006106007106008106009106010106011106012106013106014106015106016106017106018106019106020106021106022106023106024106025106026106027106028106029106030106031106032106033106034106035106036106037106038106039106040106041106042106043106044106045106046106047106048106049106050106051106052106053106054106055106056106057106058106059106060106061106062106063106064106065106066106067106068106069106070106071106072106073106074106075106076106077106078106079106080106081106082106083106084106085106086106087106088106089106090106091106092106093106094106095106096106097106098106099106100106101106102106103106104106105106106106107106108106109106110106111106112106113106114106115106116106117106118106119106120106121106122106123106124106125106126106127106128106129106130106131106132106133106134106135106136106137106138106139106140106141106142106143106144106145106146106147106148106149106150106151106152106153106154106155106156106157106158106159106160106161106162106163106164106165106166106167106168106169106170106171106172106173106174106175106176106177106178106179106180106181106182106183106184106185106186106187106188106189106190106191106192106193106194106195106196106197106198106199106200106201106202106203106204106205106206106207106208106209106210106211106212106213106214106215106216106217106218106219106220106221106222106223106224106225106226106227106228106229106230106231106232106233106234106235106236106237106238106239106240106241106242106243106244106245106246106247106248106249106250106251106252106253106254106255106256106257106258106259106260106261106262106263106264106265106266106267106268106269106270106271106272106273106274106275106276106277106278106279106280106281106282106283106284106285106286106287106288106289106290106291106292106293106294106295106296106297106298106299106300106301106302106303106304106305106306106307106308106309106310106311106312106313106314106315106316106317106318106319106320106321106322106323106324106325106326106327106328106329106330106331106332106333106334106335106336106337106338106339106340106341106342106343106344106345106346106347106348106349106350106351106352106353106354106355106356106357106358106359106360106361106362106363106364106365106366106367106368106369106370106371106372106373106374106375106376106377106378106379106380106381106382106383106384106385106386106387106388106389106390106391106392106393106394106395106396106397106398106399106400106401106402106403106404106405106406106407106408106409106410106411106412106413106414106415106416106417106418106419106420106421106422106423106424106425106426106427106428106429106430106431106432106433106434106435106436106437106438106439106440106441106442106443106444106445106446106447106448106449106450106451106452106453106454106455106456106457106458106459106460106461106462106463106464106465106466106467106468106469106470106471106472106473106474106475106476106477106478106479106480106481106482106483106484106485106486106487106488106489106490106491106492106493106494106495106496106497106498106499106500106501106502106503106504106505106506106507106508106509106510106511106512106513106514106515106516106517106518106519106520106521106522106523106524106525106526106527106528106529106530106531106532106533106534106535106536106537106538106539106540106541106542106543106544106545106546106547106548106549106550106551106552106553106554106555106556106557106558106559106560106561106562106563106564106565106566106567106568106569106570106571106572106573106574106575106576106577106578106579106580106581106582106583106584106585106586106587106588106589106590106591106592106593106594106595106596106597106598106599106600106601106602106603106604106605106606106607106608106609106610106611106612106613106614106615106616106617106618106619106620106621106622106623106624106625106626106627106628106629106630106631106632106633106634106635106636106637106638106639106640106641106642106643106644106645106646106647106648106649106650106651106652106653106654106655106656106657106658106659106660106661106662106663106664106665106666106667106668106669106670106671106672106673106674106675106676106677106678106679106680106681106682106683106684106685106686106687106688106689106690106691106692106693106694106695106696106697106698106699106700106701106702106703106704106705106706106707106708106709106710106711106712106713106714106715106716106717106718106719106720106721106722106723106724106725106726106727106728106729106730106731106732106733106734106735106736106737106738106739106740106741106742106743106744106745106746106747106748106749106750106751106752106753106754106755106756106757106758106759106760106761106762106763106764106765106766106767106768106769106770106771106772106773106774106775106776106777106778106779106780106781106782106783106784106785106786106787106788106789106790106791106792106793106794106795106796106797106798106799106800106801106802106803106804106805106806106807106808106809106810106811106812106813106814106815106816106817106818106819106820106821106822106823106824106825106826106827106828106829106830106831106832106833106834106835106836106837106838106839106840106841106842106843106844106845106846106847106848106849106850106851106852106853106854106855106856106857106858106859106860106861106862106863106864106865106866106867106868106869106870106871106872106873106874106875106876106877106878106879106880106881106882106883106884106885106886106887106888106889106890106891106892106893106894106895106896106897106898106899106900106901106902106903106904106905106906106907106908106909106910106911106912106913106914106915106916106917106918106919106920106921106922106923106924106925106926106927106928106929106930106931106932106933106934106935106936106937106938106939106940106941106942106943106944106945106946106947106948106949106950106951106952106953106954106955106956106957106958106959106960106961106962106963106964106965106966106967106968106969106970106971106972106973106974106975106976106977106978106979106980106981106982106983106984106985106986106987106988106989106990106991106992106993106994106995106996106997106998106999107000107001107002107003107004107005107006107007107008107009107010107011107012107013107014107015107016107017107018107019107020107021107022107023107024107025107026107027107028107029107030107031107032107033107034107035107036107037107038107039107040107041107042107043107044107045107046107047107048107049107050107051107052107053107054107055107056107057107058107059107060107061107062107063107064107065107066107067107068107069107070107071107072107073107074107075107076107077107078107079107080107081107082107083107084107085107086107087107088107089107090107091107092107093107094107095107096107097107098107099107100107101107102107103107104107105107106107107107108107109107110107111107112107113107114107115107116107117107118107119107120107121107122107123107124107125107126107127107128107129107130107131107132107133107134107135107136107137107138107139107140107141107142107143107144107145107146107147107148107149107150107151107152107153107154107155107156107157107158107159107160107161107162107163107164107165107166107167107168107169107170107171107172107173107174107175107176107177107178107179107180107181107182107183107184107185107186107187107188107189107190107191107192107193107194107195107196107197107198107199107200107201107202107203107204107205107206107207107208107209107210107211107212107213107214107215107216107217107218107219107220107221107222107223107224107225107226107227107228107229107230107231107232107233107234107235107236107237107238107239107240107241107242107243107244107245107246107247107248107249107250107251107252107253107254107255107256107257107258107259107260107261107262107263107264107265107266107267107268107269107270107271107272107273107274107275107276107277107278107279107280107281107282107283107284107285107286107287107288107289107290107291107292107293107294107295107296107297107298107299107300107301107302107303107304107305107306107307107308107309107310107311107312107313107314107315107316107317107318107319107320107321107322107323107324107325107326107327107328107329107330107331107332107333107334107335107336107337107338107339107340107341107342107343107344107345107346107347107348107349107350107351107352107353107354107355107356107357107358107359107360107361107362107363107364107365107366107367107368107369107370107371107372107373107374107375107376107377107378107379107380107381107382107383107384107385107386107387107388107389107390107391107392107393107394107395107396107397107398107399107400107401107402107403107404107405107406107407107408107409107410107411107412107413107414107415107416107417107418107419107420107421107422107423107424107425107426107427107428107429107430107431107432107433107434107435107436107437107438107439107440107441107442107443107444107445107446107447107448107449107450107451107452107453107454107455107456107457107458107459107460107461107462107463107464107465107466107467107468107469107470107471107472107473107474107475107476107477107478107479107480107481107482107483107484107485107486107487107488107489107490107491107492107493107494107495107496107497107498107499107500107501107502107503107504107505107506107507107508107509107510107511107512107513107514107515107516107517107518107519107520107521107522107523107524107525107526107527107528107529107530107531107532107533107534107535107536107537107538107539107540107541107542107543107544107545107546107547107548107549107550107551107552107553107554107555107556107557107558107559107560107561107562107563107564107565107566107567107568107569107570107571107572107573107574107575107576107577107578107579107580107581107582107583107584107585107586107587107588107589107590107591107592107593107594107595107596107597107598107599107600107601107602107603107604107605107606107607107608107609107610107611107612107613107614107615107616107617107618107619107620107621107622107623107624107625107626107627107628107629107630107631107632107633107634107635107636107637107638107639107640107641107642107643107644107645107646107647107648107649107650107651107652107653107654107655107656107657107658107659107660107661107662107663107664107665107666107667107668107669107670107671107672107673107674107675107676107677107678107679107680107681107682107683107684107685107686107687107688107689107690107691107692107693107694107695107696107697107698107699107700107701107702107703107704107705107706107707107708107709107710107711107712107713107714107715107716107717107718107719107720107721107722107723107724107725107726107727107728107729107730107731107732107733107734107735107736107737107738107739107740107741107742107743107744107745107746107747107748107749107750107751107752107753107754107755107756107757107758107759107760107761107762107763107764107765107766107767107768107769107770107771107772107773107774107775107776107777107778107779107780107781107782107783107784107785107786107787107788107789107790107791107792107793107794107795107796107797107798107799107800107801107802107803107804107805107806107807107808107809107810107811107812107813107814107815107816107817107818107819107820107821107822107823107824107825107826107827107828107829107830107831107832107833107834107835107836107837107838107839107840107841107842107843107844107845107846107847107848107849107850107851107852107853107854107855107856107857107858107859107860107861107862107863107864107865107866107867107868107869107870107871107872107873107874107875107876107877107878107879107880107881107882107883107884107885107886107887107888107889107890107891107892107893107894107895107896107897107898107899107900107901107902107903107904107905107906107907107908107909107910107911107912107913107914107915107916107917107918107919107920107921107922107923107924107925107926107927107928107929107930107931107932107933107934107935107936107937107938107939107940107941107942107943107944107945107946107947107948107949107950107951107952107953107954107955107956107957107958107959107960107961107962107963107964107965107966107967107968107969107970107971107972107973107974107975107976107977107978107979107980107981107982107983107984107985107986107987107988107989107990107991107992107993107994107995107996107997107998107999108000108001108002108003108004108005108006108007108008108009108010108011108012108013108014108015108016108017108018108019108020108021108022108023108024108025108026108027108028108029108030108031108032108033108034108035108036108037108038108039108040108041108042108043108044108045108046108047108048108049108050108051108052108053108054108055108056108057108058108059108060108061108062108063108064108065108066108067108068108069108070108071108072108073108074108075108076108077108078108079108080108081108082108083108084108085108086108087108088108089108090108091108092108093108094108095108096108097108098108099108100108101108102108103108104108105108106108107108108108109108110108111108112108113108114108115108116108117108118108119108120108121108122108123108124108125108126108127108128108129108130108131108132108133108134108135108136108137108138108139108140108141108142108143108144108145108146108147108148108149108150108151108152108153108154108155108156108157108158108159108160108161108162108163108164108165108166108167108168108169108170108171108172108173108174108175108176108177108178108179108180108181108182108183108184108185108186108187108188108189108190108191108192108193108194108195108196108197108198108199108200108201108202108203108204108205108206108207108208108209108210108211108212108213108214108215108216108217108218108219108220108221108222108223108224108225108226108227108228108229108230108231108232108233108234108235108236108237108238108239108240108241108242108243108244108245108246108247108248108249108250108251108252108253108254108255108256108257108258108259108260108261108262108263108264108265108266108267108268108269108270108271108272108273108274108275108276108277108278108279108280108281108282108283108284108285108286108287108288108289108290108291108292108293108294108295108296108297108298108299108300108301108302108303108304108305108306108307108308108309108310108311108312108313108314108315108316108317108318108319108320108321108322108323108324108325108326108327108328108329108330108331108332108333108334108335108336108337108338108339108340108341108342108343108344108345108346108347108348108349108350108351108352108353108354108355108356108357108358108359108360108361108362108363108364108365108366108367108368108369108370108371108372108373108374108375108376108377108378108379108380108381108382108383108384108385108386108387108388108389108390108391108392108393108394108395108396108397108398108399108400108401108402108403108404108405108406108407108408108409108410108411108412108413108414108415108416108417108418108419108420108421108422108423108424108425108426108427108428108429108430108431108432108433108434108435108436108437108438108439108440108441108442108443108444108445108446108447108448108449108450108451108452108453108454108455108456108457108458108459108460108461108462108463108464108465108466108467108468108469108470108471108472108473108474108475108476108477108478108479108480108481108482108483108484108485108486108487108488108489108490108491108492108493108494108495108496108497108498108499108500108501108502108503108504108505108506108507108508108509108510108511108512108513108514108515108516108517108518108519108520108521108522108523108524108525108526108527108528108529108530108531108532108533108534108535108536108537108538108539108540108541108542108543108544108545108546108547108548108549108550108551108552108553108554108555108556108557108558108559108560108561108562108563108564108565108566108567108568108569108570108571108572108573108574108575108576108577108578108579108580108581108582108583108584108585108586108587108588108589108590108591108592108593108594108595108596108597108598108599108600108601108602108603108604108605108606108607108608108609108610108611108612108613108614108615108616108617108618108619108620108621108622108623108624108625108626108627108628108629108630108631108632108633108634108635108636108637108638108639108640108641108642108643108644108645108646108647108648108649108650108651108652108653108654108655108656108657108658108659108660108661108662108663108664108665108666108667108668108669108670108671108672108673108674108675108676108677108678108679108680108681108682108683108684108685108686108687108688108689108690108691108692108693108694108695108696108697108698108699108700108701108702108703108704108705108706108707108708108709108710108711108712108713108714108715108716108717108718108719108720108721108722108723108724108725108726108727108728108729108730108731108732108733108734108735108736108737108738108739108740108741108742108743108744108745108746108747108748108749108750108751108752108753108754108755108756108757108758108759108760108761108762108763108764108765108766108767108768108769108770108771108772108773108774108775108776108777108778108779108780108781108782108783108784108785108786108787108788108789108790108791108792108793108794108795108796108797108798108799108800108801108802108803108804108805108806108807108808108809108810108811108812108813108814108815108816108817108818108819108820108821108822108823108824108825108826108827108828108829108830108831108832108833108834108835108836108837108838108839108840108841108842108843108844108845108846108847108848108849108850108851108852108853108854108855108856108857108858108859108860108861108862108863108864108865108866108867108868108869108870108871108872108873108874108875108876108877108878108879108880108881108882108883108884108885108886108887108888108889108890108891108892108893108894108895108896108897108898108899108900108901108902108903108904108905108906108907108908108909108910108911108912108913108914108915108916108917108918108919108920108921108922108923108924108925108926108927108928108929108930108931108932108933108934108935108936108937108938108939108940108941108942108943108944108945108946108947108948108949108950108951108952108953108954108955108956108957108958108959108960108961108962108963108964108965108966108967108968108969108970108971108972108973108974108975108976108977108978108979108980108981108982108983108984108985108986108987108988108989108990108991108992108993108994108995108996108997108998108999109000109001109002109003109004109005109006109007109008109009109010109011109012109013109014109015109016109017109018109019109020109021109022109023109024109025109026109027109028109029109030109031109032109033109034109035109036109037109038109039109040109041109042109043109044109045109046109047109048109049109050109051109052109053109054109055109056109057109058109059109060109061109062109063109064109065109066109067109068109069109070109071109072109073109074109075109076109077109078109079109080109081109082109083109084109085109086109087109088109089109090109091109092109093109094109095109096109097109098109099109100109101109102109103109104109105109106109107109108109109109110109111109112109113109114109115109116109117109118109119109120109121109122109123109124109125109126109127109128109129109130109131109132109133109134109135109136109137109138109139109140109141109142109143109144109145109146109147109148109149109150109151109152109153109154109155109156109157109158109159109160109161109162109163109164109165109166109167109168109169109170109171109172109173109174109175109176109177109178109179109180109181109182109183109184109185109186109187109188109189109190109191109192109193109194109195109196109197109198109199109200109201109202109203109204109205109206109207109208109209109210109211109212109213109214109215109216109217109218109219109220109221109222109223109224109225109226109227109228109229109230109231109232109233109234109235109236109237109238109239109240109241109242109243109244109245109246109247109248109249109250109251109252109253109254109255109256109257109258109259109260109261109262109263109264109265109266109267109268109269109270109271109272109273109274109275109276109277109278109279109280109281109282109283109284109285109286109287109288109289109290109291109292109293109294109295109296109297109298109299109300109301109302109303109304109305109306109307109308109309109310109311109312109313109314109315109316109317109318109319109320109321109322109323109324109325109326109327109328109329109330109331109332109333109334109335109336109337109338109339109340109341109342109343109344109345109346109347109348109349109350109351109352109353109354109355109356109357109358109359109360109361109362109363109364109365109366109367109368109369109370109371109372109373109374109375109376109377109378109379109380109381109382109383109384109385109386109387109388109389109390109391109392109393109394109395109396109397109398109399109400109401109402109403109404109405109406109407109408109409109410109411109412109413109414109415109416109417109418109419109420109421109422109423109424109425109426109427109428109429109430109431109432109433109434109435109436109437109438109439109440109441109442109443109444109445109446109447109448109449109450109451109452109453109454109455109456109457109458109459109460109461109462109463109464109465109466109467109468109469109470109471109472109473109474109475109476109477109478109479109480109481109482109483109484109485109486109487109488109489109490109491109492109493109494109495109496109497109498109499109500109501109502109503109504109505109506109507109508109509109510109511109512109513109514109515109516109517109518109519109520109521109522109523109524109525109526109527109528109529109530109531109532109533109534109535109536109537109538109539109540109541109542109543109544109545109546109547109548109549109550109551109552109553109554109555109556109557109558109559109560109561109562109563109564109565109566109567109568109569109570109571109572109573109574109575109576109577109578109579109580109581109582109583109584109585109586109587109588109589109590109591109592109593109594109595109596109597109598109599109600109601109602109603109604109605109606109607109608109609109610109611109612109613109614109615109616109617109618109619109620109621109622109623109624109625109626109627109628109629109630109631109632109633109634109635109636109637109638109639109640109641109642109643109644109645109646109647109648109649109650109651109652109653109654109655109656109657109658109659109660109661109662109663109664109665109666109667109668109669109670109671109672109673109674109675109676109677109678109679109680109681109682109683109684109685109686109687109688109689109690109691109692109693109694109695109696109697109698109699109700109701109702109703109704109705109706109707109708109709109710109711109712109713109714109715109716109717109718109719109720109721109722109723109724109725109726109727109728109729109730109731109732109733109734109735109736109737109738109739109740109741109742109743109744109745109746109747109748109749109750109751109752109753109754109755109756109757109758109759109760109761109762109763109764109765109766109767109768109769109770109771109772109773109774109775109776109777109778109779109780109781109782109783109784109785109786109787109788109789109790109791109792109793109794109795109796109797109798109799109800109801109802109803109804109805109806109807109808109809109810109811109812109813109814109815109816109817109818109819109820109821109822109823109824109825109826109827109828109829109830109831109832109833109834109835109836109837109838109839109840109841109842109843109844109845109846109847109848109849109850109851109852109853109854109855109856109857109858109859109860109861109862109863109864109865109866109867109868109869109870109871109872109873109874109875109876109877109878109879109880109881109882109883109884109885109886109887109888109889109890109891109892109893109894109895109896109897109898109899109900109901109902109903109904109905109906109907109908109909109910109911109912109913109914109915109916109917109918109919109920109921109922109923109924109925109926109927109928109929109930109931109932109933109934109935109936109937109938109939109940109941109942109943109944109945109946109947109948109949109950109951109952109953109954109955109956109957109958109959109960109961109962109963109964109965109966109967109968109969109970109971109972109973109974109975109976109977109978109979109980109981109982109983109984109985109986109987109988109989109990109991109992109993109994109995109996109997109998109999110000110001110002110003110004110005110006110007110008110009110010110011110012110013110014110015110016110017110018110019110020110021110022110023110024110025110026110027110028110029110030110031110032110033110034110035110036110037110038110039110040110041110042110043110044110045110046110047110048110049110050110051110052110053110054110055110056110057110058110059110060110061110062110063110064110065110066110067110068110069110070110071110072110073110074110075110076110077110078110079110080110081110082110083110084110085110086110087110088110089110090110091110092110093110094110095110096110097110098110099110100110101110102110103110104110105110106110107110108110109110110110111110112110113110114110115110116110117110118110119110120110121110122110123110124110125110126110127110128110129110130110131110132110133110134110135110136110137110138110139110140110141110142110143110144110145110146110147110148110149110150110151110152110153110154110155110156110157110158110159110160110161110162110163110164110165110166110167110168110169110170110171110172110173110174110175110176110177110178110179110180110181110182110183110184110185110186110187110188110189110190110191110192110193110194110195110196110197110198110199110200110201110202110203110204110205110206110207110208110209110210110211110212110213110214110215110216110217110218110219110220110221110222110223110224110225110226110227110228110229110230110231110232110233110234110235110236110237110238110239110240110241110242110243110244110245110246110247110248110249110250110251110252110253110254110255110256110257110258110259110260110261110262110263110264110265110266110267110268110269110270110271110272110273110274110275110276110277110278110279110280110281110282110283110284110285110286110287110288110289110290110291110292110293110294110295110296110297110298110299110300110301110302110303110304110305110306110307110308110309110310110311110312110313110314110315110316110317110318110319110320110321110322110323110324110325110326110327110328110329110330110331110332110333110334110335110336110337110338110339110340110341110342110343110344110345110346110347110348110349110350110351110352110353110354110355110356110357110358110359110360110361110362110363110364110365110366110367110368110369110370110371110372110373110374110375110376110377110378110379110380110381110382110383110384110385110386110387110388110389110390110391110392110393110394110395110396110397110398110399110400110401110402110403110404110405110406110407110408110409110410110411110412110413110414110415110416110417110418110419110420110421110422110423110424110425110426110427110428110429110430110431110432110433110434110435110436110437110438110439110440110441110442110443110444110445110446110447110448110449110450110451110452110453110454110455110456110457110458110459110460110461110462110463110464110465110466110467110468110469110470110471110472110473110474110475110476110477110478110479110480110481110482110483110484110485110486110487110488110489110490110491110492110493110494110495110496110497110498110499110500110501110502110503110504110505110506110507110508110509110510110511110512110513110514110515110516110517110518110519110520110521110522110523110524110525110526110527110528110529110530110531110532110533110534110535110536110537110538110539110540110541110542110543110544110545110546110547110548110549110550110551110552110553110554110555110556110557110558110559110560110561110562110563110564110565110566110567110568110569110570110571110572110573110574110575110576110577110578110579110580110581110582110583110584110585110586110587110588110589110590110591110592110593110594110595110596110597110598110599110600110601110602110603110604110605110606110607110608110609110610110611110612110613110614110615110616110617110618110619110620110621110622110623110624110625110626110627110628110629110630110631110632110633110634110635110636110637110638110639110640110641110642110643110644110645110646110647110648110649110650110651110652110653110654110655110656110657110658110659110660110661110662110663110664110665110666110667110668110669110670110671110672110673110674110675110676110677110678110679110680110681110682110683110684110685110686110687110688110689110690110691110692110693110694110695110696110697110698110699110700110701110702110703110704110705110706110707110708110709110710110711110712110713110714110715110716110717110718110719110720110721110722110723110724110725110726110727110728110729110730110731110732110733110734110735110736110737110738110739110740110741110742110743110744110745110746110747110748110749110750110751110752110753110754110755110756110757110758110759110760110761110762110763110764110765110766110767110768110769110770110771110772110773110774110775110776110777110778110779110780110781110782110783110784110785110786110787110788110789110790110791110792110793110794110795110796110797110798110799110800110801110802110803110804110805110806110807110808110809110810110811110812110813110814110815110816110817110818110819110820110821110822110823110824110825110826110827110828110829110830110831110832110833110834110835110836110837110838110839110840110841110842110843110844110845110846110847110848110849110850110851110852110853110854110855110856110857110858110859110860110861110862110863110864110865110866110867110868110869110870110871110872110873110874110875110876110877110878110879110880110881110882110883110884110885110886110887110888110889110890110891110892110893110894110895110896110897110898110899110900110901110902110903110904110905110906110907110908110909110910110911110912110913110914110915110916110917110918110919110920110921110922110923110924110925110926110927110928110929110930110931110932110933110934110935110936110937110938110939110940110941110942110943110944110945110946110947110948110949110950110951110952110953110954110955110956110957110958110959110960110961110962110963110964110965110966110967110968110969110970110971110972110973110974110975110976110977110978110979110980110981110982110983110984110985110986110987110988110989110990110991110992110993110994110995110996110997110998110999111000111001111002111003111004111005111006111007111008111009111010111011111012111013111014111015111016111017111018111019111020111021111022111023111024111025111026111027111028111029111030111031111032111033111034111035111036111037111038111039111040111041111042111043111044111045111046111047111048111049111050111051111052111053111054111055111056111057111058111059111060111061111062111063111064111065111066111067111068111069111070111071111072111073111074111075111076111077111078111079111080111081111082111083111084111085111086111087111088111089111090111091111092111093111094111095111096111097111098111099111100111101111102111103111104111105111106111107111108111109111110111111111112111113111114111115111116111117111118111119111120111121111122111123111124111125111126111127111128111129111130111131111132111133111134111135111136111137111138111139111140111141111142111143111144111145111146111147111148111149111150111151111152111153111154111155111156111157111158111159111160111161111162111163111164111165111166111167111168111169111170111171111172111173111174111175111176111177111178111179111180111181111182111183111184111185111186111187111188111189111190111191111192111193111194111195111196111197111198111199111200111201111202111203111204111205111206111207111208111209111210111211111212111213111214111215111216111217111218111219111220111221111222111223111224111225111226111227111228111229111230111231111232111233111234111235111236111237111238111239111240111241111242111243111244111245111246111247111248111249111250111251111252111253111254111255111256111257111258111259111260111261111262111263111264111265111266111267111268111269111270111271111272111273111274111275111276111277111278111279111280111281111282111283111284111285111286111287111288111289111290111291111292111293111294111295111296111297111298111299111300111301111302111303111304111305111306111307111308111309111310111311111312111313111314111315111316111317111318111319111320111321111322111323111324111325111326111327111328111329111330111331111332111333111334111335111336111337111338111339111340111341111342111343111344111345111346111347111348111349111350111351111352111353111354111355111356111357111358111359111360111361111362111363111364111365111366111367111368111369111370111371111372111373111374111375111376111377111378111379111380111381111382111383111384111385111386111387111388111389111390111391111392111393111394111395111396111397111398111399111400111401111402111403111404111405111406111407111408111409111410111411111412111413111414111415111416111417111418111419111420111421111422111423111424111425111426111427111428111429111430111431111432111433111434111435111436111437111438111439111440111441111442111443111444111445111446111447111448111449111450111451111452111453111454111455111456111457111458111459111460111461111462111463111464111465111466111467111468111469111470111471111472111473111474111475111476111477111478111479111480111481111482111483111484111485111486111487111488111489111490111491111492111493111494111495111496111497111498111499111500111501111502111503111504111505111506111507111508111509111510111511111512111513111514111515111516111517111518111519111520111521111522111523111524111525111526111527111528111529111530111531111532111533111534111535111536111537111538111539111540111541111542111543111544111545111546111547111548111549111550111551111552111553111554111555111556111557111558111559111560111561111562111563111564111565111566111567111568111569111570111571111572111573111574111575111576111577111578111579111580111581111582111583111584111585111586111587111588111589111590111591111592111593111594111595111596111597111598111599111600111601111602111603111604111605111606111607111608111609111610111611111612111613111614111615111616111617111618111619111620111621111622111623111624111625111626111627111628111629111630111631111632111633111634111635111636111637111638111639111640111641111642111643111644111645111646111647111648111649111650111651111652111653111654111655111656111657111658111659111660111661111662111663111664111665111666111667111668111669111670111671111672111673111674111675111676111677111678111679111680111681111682111683111684111685111686111687111688111689111690111691111692111693111694111695111696111697111698111699111700111701111702111703111704111705111706111707111708111709111710111711111712111713111714111715111716111717111718111719111720111721111722111723111724111725111726111727111728111729111730111731111732111733111734111735111736111737111738111739111740111741111742111743111744111745111746111747111748111749111750111751111752111753111754111755111756111757111758111759111760111761111762111763111764111765111766111767111768111769111770111771111772111773111774111775111776111777111778111779111780111781111782111783111784111785111786111787111788111789111790111791111792111793111794111795111796111797111798111799111800111801111802111803111804111805111806111807111808111809111810111811111812111813111814111815111816111817111818111819111820111821111822111823111824111825111826111827111828111829111830111831111832111833111834111835111836111837111838111839111840111841111842111843111844111845111846111847111848111849111850111851111852111853111854111855111856111857111858111859111860111861111862111863111864111865111866111867111868111869111870111871111872111873111874111875111876111877111878111879111880111881111882111883111884111885111886111887111888111889111890111891111892111893111894111895111896111897111898111899111900111901111902111903111904111905111906111907111908111909111910111911111912111913111914111915111916111917111918111919111920111921111922111923111924111925111926111927111928111929111930111931111932111933111934111935111936111937111938111939111940111941111942111943111944111945111946111947111948111949111950111951111952111953111954111955111956111957111958111959111960111961111962111963111964111965111966111967111968111969111970111971111972111973111974111975111976111977111978111979111980111981111982111983111984111985111986111987111988111989111990111991111992111993111994111995111996111997111998111999112000112001112002112003112004112005112006112007112008112009112010112011112012112013112014112015112016112017112018112019112020112021112022112023112024112025112026112027112028112029112030112031112032112033112034112035112036112037112038112039112040112041112042112043112044112045112046112047112048112049112050112051112052112053112054112055112056112057112058112059112060112061112062112063112064112065112066112067112068112069112070112071112072112073112074112075112076112077112078112079112080112081112082112083112084112085112086112087112088112089112090112091112092112093112094112095112096112097112098112099112100112101112102112103112104112105112106112107112108112109112110112111112112112113112114112115112116112117112118112119112120112121112122112123112124112125112126112127112128112129112130112131112132112133112134112135112136112137112138112139112140112141112142112143112144112145112146112147112148112149112150112151112152112153112154112155112156112157112158112159112160112161112162112163112164112165112166112167112168112169112170112171112172112173112174112175112176112177112178112179112180112181112182112183112184112185112186112187112188112189112190112191112192112193112194112195112196112197112198112199112200112201112202112203112204112205112206112207112208112209112210112211112212112213112214112215112216112217112218112219112220112221112222112223112224112225112226112227112228112229112230112231112232112233112234112235112236112237112238112239112240112241112242112243112244112245112246112247112248112249112250112251112252112253112254112255112256112257112258112259112260112261112262112263112264112265112266112267112268112269112270112271112272112273112274112275112276112277112278112279112280112281112282112283112284112285112286112287112288112289112290112291112292112293112294112295112296112297112298112299112300112301112302112303112304112305112306112307112308112309112310112311112312112313112314112315112316112317112318112319112320112321112322112323112324112325112326112327112328112329112330112331112332112333112334112335112336112337112338112339112340112341112342112343112344112345112346112347112348112349112350112351112352112353112354112355112356112357112358112359112360112361112362112363112364112365112366112367112368112369112370112371112372112373112374112375112376112377112378112379112380112381112382112383112384112385112386112387112388112389112390112391112392112393112394112395112396112397112398112399112400112401112402112403112404112405112406112407112408112409112410112411112412112413112414112415112416112417112418112419112420112421112422112423112424112425112426112427112428112429112430112431112432112433112434112435112436112437112438112439112440112441112442112443112444112445112446112447112448112449112450112451112452112453112454112455112456112457112458112459112460112461112462112463112464112465112466112467112468112469112470112471112472112473112474112475112476112477112478112479112480112481112482112483112484112485112486112487112488112489112490112491112492112493112494112495112496112497112498112499112500112501112502112503112504112505112506112507112508112509112510112511112512112513112514112515112516112517112518112519112520112521112522112523112524112525112526112527112528112529112530112531112532112533112534112535112536112537112538112539112540112541112542112543112544112545112546112547112548112549112550112551112552112553112554112555112556112557112558112559112560112561112562112563112564112565112566112567112568112569112570112571112572112573112574112575112576112577112578112579112580112581112582112583112584112585112586112587112588112589112590112591112592112593112594112595112596112597112598112599112600112601112602112603112604112605112606112607112608112609112610112611112612112613112614112615112616112617112618112619112620112621112622112623112624112625112626112627112628112629112630112631112632112633112634112635112636112637112638112639112640112641112642112643112644112645112646112647112648112649112650112651112652112653112654112655112656112657112658112659112660112661112662112663112664112665112666112667112668112669112670112671112672112673112674112675112676112677112678112679112680112681112682112683112684112685112686112687112688112689112690112691112692112693112694112695112696112697112698112699112700112701112702112703112704112705112706112707112708112709112710112711112712112713112714112715112716112717112718112719112720112721112722112723112724112725112726112727112728112729112730112731112732112733112734112735112736112737112738112739112740112741112742112743112744112745112746112747112748112749112750112751112752112753112754112755112756112757112758112759112760112761112762112763112764112765112766112767112768112769112770112771112772112773112774112775112776112777112778112779112780112781112782112783112784112785112786112787112788112789112790112791112792112793112794112795112796112797112798112799112800112801112802112803112804112805112806112807112808112809112810112811112812112813112814112815112816112817112818112819112820112821112822112823112824112825112826112827112828112829112830112831112832112833112834112835112836112837112838112839112840112841112842112843112844112845112846112847112848112849112850112851112852112853112854112855112856112857112858112859112860112861112862112863112864112865112866112867112868112869112870112871112872112873112874112875112876112877112878112879112880112881112882112883112884112885112886112887112888112889112890112891112892112893112894112895112896112897112898112899112900112901112902112903112904112905112906112907112908112909112910112911112912112913112914112915112916112917112918112919112920112921112922112923112924112925112926112927112928112929112930112931112932112933112934112935112936112937112938112939112940112941112942112943112944112945112946112947112948112949112950112951112952112953112954112955112956112957112958112959112960112961112962112963112964112965112966112967112968112969112970112971112972112973112974112975112976112977112978112979112980112981112982112983112984112985112986112987112988112989112990112991112992112993112994112995112996112997112998112999113000113001113002113003113004113005113006113007113008113009113010113011113012113013113014113015113016113017113018113019113020113021113022113023113024113025113026113027113028113029113030113031113032113033113034113035113036113037113038113039113040113041113042113043113044113045113046113047113048113049113050113051113052113053113054113055113056113057113058113059113060113061113062113063113064113065113066113067113068113069113070113071113072113073113074113075113076113077113078113079113080113081113082113083113084113085113086113087113088113089113090113091113092113093113094113095113096113097113098113099113100113101113102113103113104113105113106113107113108113109113110113111113112113113113114113115113116113117113118113119113120113121113122113123113124113125113126113127113128113129113130113131113132113133113134113135113136113137113138113139113140113141113142113143113144113145113146113147113148113149113150113151113152113153113154113155113156113157113158113159113160113161113162113163113164113165113166113167113168113169113170113171113172113173113174113175113176113177113178113179113180113181113182113183113184113185113186113187113188113189113190113191113192113193113194113195113196113197113198113199113200113201113202113203113204113205113206113207113208113209113210113211113212113213113214113215113216113217113218113219113220113221113222113223113224113225113226113227113228113229113230113231113232113233113234113235113236113237113238113239113240113241113242113243113244113245113246113247113248113249113250113251113252113253113254113255113256113257113258113259113260113261113262113263113264113265113266113267113268113269113270113271113272113273113274113275113276113277113278113279113280113281113282113283113284113285113286113287113288113289113290113291113292113293113294113295113296113297113298113299113300113301113302113303113304113305113306113307113308113309113310113311113312113313113314113315113316113317113318113319113320113321113322113323113324113325113326113327113328113329113330113331113332113333113334113335113336113337113338113339113340113341113342113343113344113345113346113347113348113349113350113351113352113353113354113355113356113357113358113359113360113361113362113363113364113365113366113367113368113369113370113371113372113373113374113375113376113377113378113379113380113381113382113383113384113385113386113387113388113389113390113391113392113393113394113395113396113397113398113399113400113401113402113403113404113405113406113407113408113409113410113411113412113413113414113415113416113417113418113419113420113421113422113423113424113425113426113427113428113429113430113431113432113433113434113435113436113437113438113439113440113441113442113443113444113445113446113447113448113449113450113451113452113453113454113455113456113457113458113459113460113461113462113463113464113465113466113467113468113469113470113471113472113473113474113475113476113477113478113479113480113481113482113483113484113485113486113487113488113489113490113491113492113493113494113495113496113497113498113499113500113501113502113503113504113505113506113507113508113509113510113511113512113513113514113515113516113517113518113519113520113521113522113523113524113525113526113527113528113529113530113531113532113533113534113535113536113537113538113539113540113541113542113543113544113545113546113547113548113549113550113551113552113553113554113555113556113557113558113559113560113561113562113563113564113565113566113567113568113569113570113571113572113573113574113575113576113577113578113579113580113581113582113583113584113585113586113587113588113589113590113591113592113593113594113595113596113597113598113599113600113601113602113603113604113605113606113607113608113609113610113611113612113613113614113615113616113617113618113619113620113621113622113623113624113625113626113627113628113629113630113631113632113633113634113635113636113637113638113639113640113641113642113643113644113645113646113647113648113649113650113651113652113653113654113655113656113657113658113659113660113661113662113663113664113665113666113667113668113669113670113671113672113673113674113675113676113677113678113679113680113681113682113683113684113685113686113687113688113689113690113691113692113693113694113695113696113697113698113699113700113701113702113703113704113705113706113707113708113709113710113711113712113713113714113715113716113717113718113719113720113721113722113723113724113725113726113727113728113729113730113731113732113733113734113735113736113737113738113739113740113741113742113743113744113745113746113747113748113749113750113751113752113753113754113755113756113757113758113759113760113761113762113763113764113765113766113767113768113769113770113771113772113773113774113775113776113777113778113779113780113781113782113783113784113785113786113787113788113789113790113791113792113793113794113795113796113797113798113799113800113801113802113803113804113805113806113807113808113809113810113811113812113813113814113815113816113817113818113819113820113821113822113823113824113825113826113827113828113829113830113831113832113833113834113835113836113837113838113839113840113841113842113843113844113845113846113847113848113849113850113851113852113853113854113855113856113857113858113859113860113861113862113863113864113865113866113867113868113869113870113871113872113873113874113875113876113877113878113879113880113881113882113883113884113885113886113887113888113889113890113891113892113893113894113895113896113897113898113899113900113901113902113903113904113905113906113907113908113909113910113911113912113913113914113915113916113917113918113919113920113921113922113923113924113925113926113927113928113929113930113931113932113933113934113935113936113937113938113939113940113941113942113943113944113945113946113947113948113949113950113951113952113953113954113955113956113957113958113959113960113961113962113963113964113965113966113967113968113969113970113971113972113973113974113975113976113977113978113979113980113981113982113983113984113985113986113987113988113989113990113991113992113993113994113995113996113997113998113999114000114001114002114003114004114005114006114007114008114009114010114011114012114013114014114015114016114017114018114019114020114021114022114023114024114025114026114027114028114029114030114031114032114033114034114035114036114037114038114039114040114041114042114043114044114045114046114047114048114049114050114051114052114053114054114055114056114057114058114059114060114061114062114063114064114065114066114067114068114069114070114071114072114073114074114075114076114077114078114079114080114081114082114083114084114085114086114087114088114089114090114091114092114093114094114095114096114097114098114099114100114101114102114103114104114105114106114107114108114109114110114111114112114113114114114115114116114117114118114119114120114121114122114123114124114125114126114127114128114129114130114131114132114133114134114135114136114137114138114139114140114141114142114143114144114145114146114147114148114149114150114151114152114153114154114155114156114157114158114159114160114161114162114163114164114165114166114167114168114169114170114171114172114173114174114175114176114177114178114179114180114181114182114183114184114185114186114187114188114189114190114191114192114193114194114195114196114197114198114199114200114201114202114203114204114205114206114207114208114209114210114211114212114213114214114215114216114217114218114219114220114221114222114223114224114225114226114227114228114229114230114231114232114233114234114235114236114237114238114239114240114241114242114243114244114245114246114247114248114249114250114251114252114253114254114255114256114257114258114259114260114261114262114263114264114265114266114267114268114269114270114271114272114273114274114275114276114277114278114279114280114281114282114283114284114285114286114287114288114289114290114291114292114293114294114295114296114297114298114299114300114301114302114303114304114305114306114307114308114309114310114311114312114313114314114315114316114317114318114319114320114321114322114323114324114325114326114327114328114329114330114331114332114333114334114335114336114337114338114339114340114341114342114343114344114345114346114347114348114349114350114351114352114353114354114355114356114357114358114359114360114361114362114363114364114365114366114367114368114369114370114371114372114373114374114375114376114377114378114379114380114381114382114383114384114385114386114387114388114389114390114391114392114393114394114395114396114397114398114399114400114401114402114403114404114405114406114407114408114409114410114411114412114413114414114415114416114417114418114419114420114421114422114423114424114425114426114427114428114429114430114431114432114433114434114435114436114437114438114439114440114441114442114443114444114445114446114447114448114449114450114451114452114453114454114455114456114457114458114459114460114461114462114463114464114465114466114467114468114469114470114471114472114473114474114475114476114477114478114479114480114481114482114483114484114485114486114487114488114489114490114491114492114493114494114495114496114497114498114499114500114501114502114503114504114505114506114507114508114509114510114511114512114513114514114515114516114517114518114519114520114521114522114523114524114525114526114527114528114529114530114531114532114533114534114535114536114537114538114539114540114541114542114543114544114545114546114547114548114549114550114551114552114553114554114555114556114557114558114559114560114561114562114563114564114565114566114567114568114569114570114571114572114573114574114575114576114577114578114579114580114581114582114583114584114585114586114587114588114589114590114591114592114593114594114595114596114597114598114599114600114601114602114603114604114605114606114607114608114609114610114611114612114613114614114615114616114617114618114619114620114621114622114623114624114625114626114627114628114629114630114631114632114633114634114635114636114637114638114639114640114641114642114643114644114645114646114647114648114649114650114651114652114653114654114655114656114657114658114659114660114661114662114663114664114665114666114667114668114669114670114671114672114673114674114675114676114677114678114679114680114681114682114683114684114685114686114687114688114689114690114691114692114693114694114695114696114697114698114699114700114701114702114703114704114705114706114707114708114709114710114711114712114713114714114715114716114717114718114719114720114721114722114723114724114725114726114727114728114729114730114731114732114733114734114735114736114737114738114739114740114741114742114743114744114745114746114747114748114749114750114751114752114753114754114755114756114757114758114759114760114761114762114763114764114765114766114767114768114769114770114771114772114773114774114775114776114777114778114779114780114781114782114783114784114785114786114787114788114789114790114791114792114793114794114795114796114797114798114799114800114801114802114803114804114805114806114807114808114809114810114811114812114813114814114815114816114817114818114819114820114821114822114823114824114825114826114827114828114829114830114831114832114833114834114835114836114837114838114839114840114841114842114843114844114845114846114847114848114849114850114851114852114853114854114855114856114857114858114859114860114861114862114863114864114865114866114867114868114869114870114871114872114873114874114875114876114877114878114879114880114881114882114883114884114885114886114887114888114889114890114891114892114893114894114895114896114897114898114899114900114901114902114903114904114905114906114907114908114909114910114911114912114913114914114915114916114917114918114919114920114921114922114923114924114925114926114927114928114929114930114931114932114933114934114935114936114937114938114939114940114941114942114943114944114945114946114947114948114949114950114951114952114953114954114955114956114957114958114959114960114961114962114963114964114965114966114967114968114969114970114971114972114973114974114975114976114977114978114979114980114981114982114983114984114985114986114987114988114989114990114991114992114993114994114995114996114997114998114999115000115001115002115003115004115005115006115007115008115009115010115011115012115013115014115015115016115017115018115019115020115021115022115023115024115025115026115027115028115029115030115031115032115033115034115035115036115037115038115039115040115041115042115043115044115045115046115047115048115049115050115051115052115053115054115055115056115057115058115059115060115061115062115063115064115065115066115067115068115069115070115071115072115073115074115075115076115077115078115079115080115081115082115083115084115085115086115087115088115089115090115091115092115093115094115095115096115097115098115099115100115101115102115103115104115105115106115107115108115109115110115111115112115113115114115115115116115117115118115119115120115121115122115123115124115125115126115127115128115129115130115131115132115133115134115135115136115137115138115139115140115141115142115143115144115145115146115147115148115149115150115151115152115153115154115155115156115157115158115159115160115161115162115163115164115165115166115167115168115169115170115171115172115173115174115175115176115177115178115179115180115181115182115183115184115185115186115187115188115189115190115191115192115193115194115195115196115197115198115199115200115201115202115203115204115205115206115207115208115209115210115211115212115213115214115215115216115217115218115219115220115221115222115223115224115225115226115227115228115229115230115231115232115233115234115235115236115237115238115239115240115241115242115243115244115245115246115247115248115249115250115251115252115253115254115255115256115257115258115259115260115261115262115263115264115265115266115267115268115269115270115271115272115273115274115275115276115277115278115279115280115281115282115283115284115285115286115287115288115289115290115291115292115293115294115295115296115297115298115299115300115301115302115303115304115305115306115307115308115309115310115311115312115313115314115315115316115317115318115319115320115321115322115323115324115325115326115327115328115329115330115331115332115333115334115335115336115337115338115339115340115341115342115343115344115345115346115347115348115349115350115351115352115353115354115355115356115357115358115359115360115361115362115363115364115365115366115367115368115369115370115371115372115373115374115375115376115377115378115379115380115381115382115383115384115385115386115387115388115389115390115391115392115393115394115395115396115397115398115399115400115401115402115403115404115405115406115407115408115409115410115411115412115413115414115415115416115417115418115419115420115421115422115423115424115425115426115427115428115429115430115431115432115433115434115435115436115437115438115439115440115441115442115443115444115445115446115447115448115449115450115451115452115453115454115455115456115457115458115459115460115461115462115463115464115465115466115467115468115469115470115471115472115473115474115475115476115477115478115479115480115481115482115483115484115485115486115487115488115489115490115491115492115493115494115495115496115497115498115499115500115501115502115503115504115505115506115507115508115509115510115511115512115513115514115515115516115517115518115519115520115521115522115523115524115525115526115527115528115529115530115531115532115533115534115535115536115537115538115539115540115541115542115543115544115545115546115547115548115549115550115551115552115553115554115555115556115557115558115559115560115561115562115563115564115565115566115567115568115569115570115571115572115573115574115575115576115577115578115579115580115581115582115583115584115585115586115587115588115589115590115591115592115593115594115595115596115597115598115599115600115601115602115603115604115605115606115607115608115609115610115611115612115613115614115615115616115617115618115619115620115621115622115623115624115625115626115627115628115629115630115631115632115633115634115635115636115637115638115639115640115641115642115643115644115645115646115647115648115649115650115651115652115653115654115655115656115657115658115659115660115661115662115663115664115665115666115667115668115669115670115671115672115673115674115675115676115677115678115679115680115681115682115683115684115685115686115687115688115689115690115691115692115693115694115695115696115697115698115699115700115701115702115703115704115705115706115707115708115709115710115711115712115713115714115715115716115717115718115719115720115721115722115723115724115725115726115727115728115729115730115731115732115733115734115735115736115737115738115739115740115741115742115743115744115745115746115747115748115749115750115751115752115753115754115755115756115757115758115759115760115761115762115763115764115765115766115767115768115769115770115771115772115773115774115775115776115777115778115779115780115781115782115783115784115785115786115787115788115789115790115791115792115793115794115795115796115797115798115799115800115801115802115803115804115805115806115807115808115809115810115811115812115813115814115815115816115817115818115819115820115821115822115823115824115825115826115827115828115829115830115831115832115833115834115835115836115837115838115839115840115841115842115843115844115845115846115847115848115849115850115851115852115853115854115855115856115857115858115859115860115861115862115863115864115865115866115867115868115869115870115871115872115873115874115875115876115877115878115879115880115881115882115883115884115885115886115887115888115889115890115891115892115893115894115895115896115897115898115899115900115901115902115903115904115905115906115907115908115909115910115911115912115913115914115915115916115917115918115919115920115921115922115923115924115925115926115927115928115929115930115931115932115933115934115935115936115937115938115939115940115941115942115943115944115945115946115947115948115949115950115951115952115953115954115955115956115957115958115959115960115961115962115963115964115965115966115967115968115969115970115971115972115973115974115975115976115977115978115979115980115981115982115983115984115985115986115987115988115989115990115991115992115993115994115995115996115997115998115999116000116001116002116003116004116005116006116007116008116009116010116011116012116013116014116015116016116017116018116019116020116021116022116023116024116025116026116027116028116029116030116031116032116033116034116035116036116037116038116039116040116041116042116043116044116045116046116047116048116049116050116051116052116053116054116055116056116057116058116059116060116061116062116063116064116065116066116067116068116069116070116071116072116073116074116075116076116077116078116079116080116081116082116083116084116085116086116087116088116089116090116091116092116093116094116095116096116097116098116099116100116101116102116103116104116105116106116107116108116109116110116111116112116113116114116115116116116117116118116119116120116121116122116123116124116125116126116127116128116129116130116131116132116133116134116135116136116137116138116139116140116141116142116143116144116145116146116147116148116149116150116151116152116153116154116155116156116157116158116159116160116161116162116163116164116165116166116167116168116169116170116171116172116173116174116175116176116177116178116179116180116181116182116183116184116185116186116187116188116189116190116191116192116193116194116195116196116197116198116199116200116201116202116203116204116205116206116207116208116209116210116211116212116213116214116215116216116217116218116219116220116221116222116223116224116225116226116227116228116229116230116231116232116233116234116235116236116237116238116239116240116241116242116243116244116245116246116247116248116249116250116251116252116253116254116255116256116257116258116259116260116261116262116263116264116265116266116267116268116269116270116271116272116273116274116275116276116277116278116279116280116281116282116283116284116285116286116287116288116289116290116291116292116293116294116295116296116297116298116299116300116301116302116303116304116305116306116307116308116309116310116311116312116313116314116315116316116317116318116319116320116321116322116323116324116325116326116327116328116329116330116331116332116333116334116335116336116337116338116339116340116341116342116343116344116345116346116347116348116349116350116351116352116353116354116355116356116357116358116359116360116361116362116363116364116365116366116367116368116369116370116371116372116373116374116375116376116377116378116379116380116381116382116383116384116385116386116387116388116389116390116391116392116393116394116395116396116397116398116399116400116401116402116403116404116405116406116407116408116409116410116411116412116413116414116415116416116417116418116419116420116421116422116423116424116425116426116427116428116429116430116431116432116433116434116435116436116437116438116439116440116441116442116443116444116445116446116447116448116449116450116451116452116453116454116455116456116457116458116459116460116461116462116463116464116465116466116467116468116469116470116471116472116473116474116475116476116477116478116479116480116481116482116483116484116485116486116487116488116489116490116491116492116493116494116495116496116497116498116499116500116501116502116503116504116505116506116507116508116509116510116511116512116513116514116515116516116517116518116519116520116521116522116523116524116525116526116527116528116529116530116531116532116533116534116535116536116537116538116539116540116541116542116543116544116545116546116547116548116549116550116551116552116553116554116555116556116557116558116559116560116561116562116563116564116565116566116567116568116569116570116571116572116573116574116575116576116577116578116579116580116581116582116583116584116585116586116587116588116589116590116591116592116593116594116595116596116597116598116599116600116601116602116603116604116605116606116607116608116609116610116611116612116613116614116615116616116617116618116619116620116621116622116623116624116625116626116627116628116629116630116631116632116633116634116635116636116637116638116639116640116641116642116643116644116645116646116647116648116649116650116651116652116653116654116655116656116657116658116659116660116661116662116663116664116665116666116667116668116669116670116671116672116673116674116675116676116677116678116679116680116681116682116683116684116685116686116687116688116689116690116691116692116693116694116695116696116697116698116699116700116701116702116703116704116705116706116707116708116709116710116711116712116713116714116715116716116717116718116719116720116721116722116723116724116725116726116727116728116729116730116731116732116733116734116735116736116737116738116739116740116741116742116743116744116745116746116747116748116749116750116751116752116753116754116755116756116757116758116759116760116761116762116763116764116765116766116767116768116769116770116771116772116773116774116775116776116777116778116779116780116781116782116783116784116785116786116787116788116789116790116791116792116793116794116795116796116797116798116799116800116801116802116803116804116805116806116807116808116809116810116811116812116813116814116815116816116817116818116819116820116821116822116823116824116825116826116827116828116829116830116831116832116833116834116835116836116837116838116839116840116841116842116843116844116845116846116847116848116849116850116851116852116853116854116855116856116857116858116859116860116861116862116863116864116865116866116867116868116869116870116871116872116873116874116875116876116877116878116879116880116881116882116883116884116885116886116887116888116889116890116891116892116893116894116895116896116897116898116899116900116901116902116903116904116905116906116907116908116909116910116911116912116913116914116915116916116917116918116919116920116921116922116923116924116925116926116927116928116929116930116931116932116933116934116935116936116937116938116939116940116941116942116943116944116945116946116947116948116949116950116951116952116953116954116955116956116957116958116959116960116961116962116963116964116965116966116967116968116969116970116971116972116973116974116975116976116977116978116979116980116981116982116983116984116985116986116987116988116989116990116991116992116993116994116995116996116997116998116999117000117001117002117003117004117005117006117007117008117009117010117011117012117013117014117015117016117017117018117019117020117021117022117023117024117025117026117027117028117029117030117031117032117033117034117035117036117037117038117039117040117041117042117043117044117045117046117047117048117049117050117051117052117053117054117055117056117057117058117059117060117061117062117063117064117065117066117067117068117069117070117071117072117073117074117075117076117077117078117079117080117081117082117083117084117085117086117087117088117089117090117091117092117093117094117095117096117097117098117099117100117101117102117103117104117105117106117107117108117109117110117111117112117113117114117115117116117117117118117119117120117121117122117123117124117125117126117127117128117129117130117131117132117133117134117135117136117137117138117139117140117141117142117143117144117145117146117147117148117149117150117151117152117153117154117155117156117157117158117159117160117161117162117163117164117165117166117167117168117169117170117171117172117173117174117175117176117177117178117179117180117181117182117183117184117185117186117187117188117189117190117191117192117193117194117195117196117197117198117199117200117201117202117203117204117205117206117207117208117209117210117211117212117213117214117215117216117217117218117219117220117221117222117223117224117225117226117227117228117229117230117231117232117233117234117235117236117237117238117239117240117241117242117243117244117245117246117247117248117249117250117251117252117253117254117255117256117257117258117259117260117261117262117263117264117265117266117267117268117269117270117271117272117273117274117275117276117277117278117279117280117281117282117283117284117285117286117287117288117289117290117291117292117293117294117295117296117297117298117299117300117301117302117303117304117305117306117307117308117309117310117311117312117313117314117315117316117317117318117319117320117321117322117323117324117325117326117327117328117329117330117331117332117333117334117335117336117337117338117339117340117341117342117343117344117345117346117347117348117349117350117351117352117353117354117355117356117357117358117359117360117361117362117363117364117365117366117367117368117369117370117371117372117373117374117375117376117377117378117379117380117381117382117383117384117385117386117387117388117389117390117391117392117393117394117395117396117397117398117399117400117401117402117403117404117405117406117407117408117409117410117411117412117413117414117415117416117417117418117419117420117421117422117423117424117425117426117427117428117429117430117431117432117433117434117435117436117437117438117439117440117441117442117443117444117445117446117447117448117449117450117451117452117453117454117455117456117457117458117459117460117461117462117463117464117465117466117467117468117469117470117471117472117473117474117475117476117477117478117479117480117481117482117483117484117485117486117487117488117489117490117491117492117493117494117495117496117497117498117499117500117501117502117503117504117505117506117507117508117509117510117511117512117513117514117515117516117517117518117519117520117521117522117523117524117525117526117527117528117529117530117531117532117533117534117535117536117537117538117539117540117541117542117543117544117545117546117547117548117549117550117551117552117553117554117555117556117557117558117559117560117561117562117563117564117565117566117567117568117569117570117571117572117573117574117575117576117577117578117579117580117581117582117583117584117585117586117587117588117589117590117591117592117593117594117595117596117597117598117599117600117601117602117603117604117605117606117607117608117609117610117611117612117613117614117615117616117617117618117619117620117621117622117623117624117625117626117627117628117629117630117631117632117633117634117635117636117637117638117639117640117641117642117643117644117645117646117647117648117649117650117651117652117653117654117655117656117657117658117659117660117661117662117663117664117665117666117667117668117669117670117671117672117673117674117675117676117677117678117679117680117681117682117683117684117685117686117687117688117689117690117691117692117693117694117695117696117697117698117699117700117701117702117703117704117705117706117707117708117709117710117711117712117713117714117715117716117717117718117719117720117721117722117723117724117725117726117727117728117729117730117731117732117733117734117735117736117737117738117739117740117741117742117743117744117745117746117747117748117749117750117751117752117753117754117755117756117757117758117759117760117761117762117763117764117765117766117767117768117769117770117771117772117773117774117775117776117777117778117779117780117781117782117783117784117785117786117787117788117789117790117791117792117793117794117795117796117797117798117799117800117801117802117803117804117805117806117807117808117809117810117811117812117813117814117815117816117817117818117819117820117821117822117823117824117825117826117827117828117829117830117831117832117833117834117835117836117837117838117839117840117841117842117843117844117845117846117847117848117849117850117851117852117853117854117855117856117857117858117859117860117861117862117863117864117865117866117867117868117869117870117871117872117873117874117875117876117877117878117879117880117881117882117883117884117885117886117887117888117889117890117891117892117893117894117895117896117897117898117899117900117901117902117903117904117905117906117907117908117909117910117911117912117913117914117915117916117917117918117919117920117921117922117923117924117925117926117927117928117929117930117931117932117933117934117935117936117937117938117939117940117941117942117943117944117945117946117947117948117949117950117951117952117953117954117955117956117957117958117959117960117961117962117963117964117965117966117967117968117969117970117971117972117973117974117975117976117977117978117979117980117981117982117983117984117985117986117987117988117989117990117991117992117993117994117995117996117997117998117999118000118001118002118003118004118005118006118007118008118009118010118011118012118013118014118015118016118017118018118019118020118021118022118023118024118025118026118027118028118029118030118031118032118033118034118035118036118037118038118039118040118041118042118043118044118045118046118047118048118049118050118051118052118053118054118055118056118057118058118059118060118061118062118063118064118065118066118067118068118069118070118071118072118073118074118075118076118077118078118079118080118081118082118083118084118085118086118087118088118089118090118091118092118093118094118095118096118097118098118099118100118101118102118103118104118105118106118107118108118109118110118111118112118113118114118115118116118117118118118119118120118121118122118123118124118125118126118127118128118129118130118131118132118133118134118135118136118137118138118139118140118141118142118143118144118145118146118147118148118149118150118151118152118153118154118155118156118157118158118159118160118161118162118163118164118165118166118167118168118169118170118171118172118173118174118175118176118177118178118179118180118181118182118183118184118185118186118187118188118189118190118191118192118193118194118195118196118197118198118199118200118201118202118203118204118205118206118207118208118209118210118211118212118213118214118215118216118217118218118219118220118221118222118223118224118225118226118227118228118229118230118231118232118233118234118235118236118237118238118239118240118241118242118243118244118245118246118247118248118249118250118251118252118253118254118255118256118257118258118259118260118261118262118263118264118265118266118267118268118269118270118271118272118273118274118275118276118277118278118279118280118281118282118283118284118285118286118287118288118289118290118291118292118293118294118295118296118297118298118299118300118301118302118303118304118305118306118307118308118309118310118311118312118313118314118315118316118317118318118319118320118321118322118323118324118325118326118327118328118329118330118331118332118333118334118335118336118337118338118339118340118341118342118343118344118345118346118347118348118349118350118351118352118353118354118355118356118357118358118359118360118361118362118363118364118365118366118367118368118369118370118371118372118373118374118375118376118377118378118379118380118381118382118383118384118385118386118387118388118389118390118391118392118393118394118395118396118397118398118399118400118401118402118403118404118405118406118407118408118409118410118411118412118413118414118415118416118417118418118419118420118421118422118423118424118425118426118427118428118429118430118431118432118433118434118435118436118437118438118439118440118441118442118443118444118445118446118447118448118449118450118451118452118453118454118455118456118457118458118459118460118461118462118463118464118465118466118467118468118469118470118471118472118473118474118475118476118477118478118479118480118481118482118483118484118485118486118487118488118489118490118491118492118493118494118495118496118497118498118499118500118501118502118503118504118505118506118507118508118509118510118511118512118513118514118515118516118517118518118519118520118521118522118523118524118525118526118527118528118529118530118531118532118533118534118535118536118537118538118539118540118541118542118543118544118545118546118547118548118549118550118551118552118553118554118555118556118557118558118559118560118561118562118563118564118565118566118567118568118569118570118571118572118573118574118575118576118577118578118579118580118581118582118583118584118585118586118587118588118589118590118591118592118593118594118595118596118597118598118599118600118601118602118603118604118605118606118607118608118609118610118611118612118613118614118615118616118617118618118619118620118621118622118623118624118625118626118627118628118629118630118631118632118633118634118635118636118637118638118639118640118641118642118643118644118645118646118647118648118649118650118651118652118653118654118655118656118657118658118659118660118661118662118663118664118665118666118667118668118669118670118671118672118673118674118675118676118677118678118679118680118681118682118683118684118685118686118687118688118689118690118691118692118693118694118695118696118697118698118699118700118701118702118703118704118705118706118707118708118709118710118711118712118713118714118715118716118717118718118719118720118721118722118723118724118725118726118727118728118729118730118731118732118733118734118735118736118737118738118739118740118741118742118743118744118745118746118747118748118749118750118751118752118753118754118755118756118757118758118759118760118761118762118763118764118765118766118767118768118769118770118771118772118773118774118775118776118777118778118779118780118781118782118783118784118785118786118787118788118789118790118791118792118793118794118795118796118797118798118799118800118801118802118803118804118805118806118807118808118809118810118811118812118813118814118815118816118817118818118819118820118821118822118823118824118825118826118827118828118829118830118831118832118833118834118835118836118837118838118839118840118841118842118843118844118845118846118847118848118849118850118851118852118853118854118855118856118857118858118859118860118861118862118863118864118865118866118867118868118869118870118871118872118873118874118875118876118877118878118879118880118881118882118883118884118885118886118887118888118889118890118891118892118893118894118895118896118897118898118899118900118901118902118903118904118905118906118907118908118909118910118911118912118913118914118915118916118917118918118919118920118921118922118923118924118925118926118927118928118929118930118931118932118933118934118935118936118937118938118939118940118941118942118943118944118945118946118947118948118949118950118951118952118953118954118955118956118957118958118959118960118961118962118963118964118965118966118967118968118969118970118971118972118973118974118975118976118977118978118979118980118981118982118983118984118985118986118987118988118989118990118991118992118993118994118995118996118997118998118999119000119001119002119003119004119005119006119007119008119009119010119011119012119013119014119015119016119017119018119019119020119021119022119023119024119025119026119027119028119029119030119031119032119033119034119035119036119037119038119039119040119041119042119043119044119045119046119047119048119049119050119051119052119053119054119055119056119057119058119059119060119061119062119063119064119065119066119067119068119069119070119071119072119073119074119075119076119077119078119079119080119081119082119083119084119085119086119087119088119089119090119091119092119093119094119095119096119097119098119099119100119101119102119103119104119105119106119107119108119109119110119111119112119113119114119115119116119117119118119119119120119121119122119123119124119125119126119127119128119129119130119131119132119133119134119135119136119137119138119139119140119141119142119143119144119145119146119147119148119149119150119151119152119153119154119155119156119157119158119159119160119161119162119163119164119165119166119167119168119169119170119171119172119173119174119175119176119177119178119179119180119181119182119183119184119185119186119187119188119189119190119191119192119193119194119195119196119197119198119199119200119201119202119203119204119205119206119207119208119209119210119211119212119213119214119215119216119217119218119219119220119221119222119223119224119225119226119227119228119229119230119231119232119233119234119235119236119237119238119239119240119241119242119243119244119245119246119247119248119249119250119251119252119253119254119255119256119257119258119259119260119261119262119263119264119265119266119267119268119269119270119271119272119273119274119275119276119277119278119279119280119281119282119283119284119285119286119287119288119289119290119291119292119293119294119295119296119297119298119299119300119301119302119303119304119305119306119307119308119309119310119311119312119313119314119315119316119317119318119319119320119321119322119323119324119325119326119327119328119329119330119331119332119333119334119335119336119337119338119339119340119341119342119343119344119345119346119347119348119349119350119351119352119353119354119355119356119357119358119359119360119361119362119363119364119365119366119367119368119369119370119371119372119373119374119375119376119377119378119379119380119381119382119383119384119385119386119387119388119389119390119391119392119393119394119395119396119397119398119399119400119401119402119403119404119405119406119407119408119409119410119411119412119413119414119415119416119417119418119419119420119421119422119423119424119425119426119427119428119429119430119431119432119433119434119435119436119437119438119439119440119441119442119443119444119445119446119447119448119449119450119451119452119453119454119455119456119457119458119459119460119461119462119463119464119465119466119467119468119469119470119471119472119473119474119475119476119477119478119479119480119481119482119483119484119485119486119487119488119489119490119491119492119493119494119495119496119497119498119499119500119501119502119503119504119505119506119507119508119509119510119511119512119513119514119515119516119517119518119519119520119521119522119523119524119525119526119527119528119529119530119531119532119533119534119535119536119537119538119539119540119541119542119543119544119545119546119547119548119549119550119551119552119553119554119555119556119557119558119559119560119561119562119563119564119565119566119567119568119569119570119571119572119573119574119575119576119577119578119579119580119581119582119583119584119585119586119587119588119589119590119591119592119593119594119595119596119597119598119599119600119601119602119603119604119605119606119607119608119609119610119611119612119613119614119615119616119617119618119619119620119621119622119623119624119625119626119627119628119629119630119631119632119633119634119635119636119637119638119639119640119641119642119643119644119645119646119647119648119649119650119651119652119653119654119655119656119657119658119659119660119661119662119663119664119665119666119667119668119669119670119671119672119673119674119675119676119677119678119679119680119681119682119683119684119685119686119687119688119689119690119691119692119693119694119695119696119697119698119699119700119701119702119703119704119705119706119707119708119709119710119711119712119713119714119715119716119717119718119719119720119721119722119723119724119725119726119727119728119729119730119731119732119733119734119735119736119737119738119739119740119741119742119743119744119745119746119747119748119749119750119751119752119753119754119755119756119757119758119759119760119761119762119763119764119765119766119767119768119769119770119771119772119773119774119775119776119777119778119779119780119781119782119783119784119785119786119787119788119789119790119791119792119793119794119795119796119797119798119799119800119801119802119803119804119805119806119807119808119809119810119811119812119813119814119815119816119817119818119819119820119821119822119823119824119825119826119827119828119829119830119831119832119833119834119835119836119837119838119839119840119841119842119843119844119845119846119847119848119849119850119851119852119853119854119855119856119857119858119859119860119861119862119863119864119865119866119867119868119869119870119871119872119873119874119875119876119877119878119879119880119881119882119883119884119885119886119887119888119889119890119891119892119893119894119895119896119897119898119899119900119901119902119903119904119905119906119907119908119909119910119911119912119913119914119915119916119917119918119919119920119921119922119923119924119925119926119927119928119929119930119931119932119933119934119935119936119937119938119939119940119941119942119943119944119945119946119947119948119949119950119951119952119953119954119955119956119957119958119959119960119961119962119963119964119965119966119967119968119969119970119971119972119973119974119975119976119977119978119979119980119981119982119983119984119985119986119987119988119989119990119991119992119993119994119995119996119997119998119999120000120001120002120003120004120005120006120007120008120009120010120011120012120013120014120015120016120017120018120019120020120021120022120023120024120025120026120027120028120029120030120031120032120033120034120035120036120037120038120039120040120041120042120043120044120045120046120047120048120049120050120051120052120053120054120055120056120057120058120059120060120061120062120063120064120065120066120067120068120069120070120071120072120073120074120075120076120077120078120079120080120081120082120083120084120085120086120087120088120089120090120091120092120093120094120095120096120097120098120099120100120101120102120103120104120105120106120107120108120109120110120111120112120113120114120115120116120117120118120119120120120121120122120123120124120125120126120127120128120129120130120131120132120133120134120135120136120137120138120139120140120141120142120143120144120145120146120147120148120149120150120151120152120153120154120155120156120157120158120159120160120161120162120163120164120165120166120167120168120169120170120171120172120173120174120175120176120177120178120179120180120181120182120183120184120185120186120187120188120189120190120191120192120193120194120195120196120197120198120199120200120201120202120203120204120205120206120207120208120209120210120211120212120213120214120215120216120217120218120219120220120221120222120223120224120225120226120227120228120229120230120231120232120233120234120235120236120237120238120239120240120241120242120243120244120245120246120247120248120249120250120251120252120253120254120255120256120257120258120259120260120261120262120263120264120265120266120267120268120269120270120271120272120273120274120275120276120277120278120279120280120281120282120283120284120285120286120287120288120289120290120291120292120293120294120295120296120297120298120299120300120301120302120303120304120305120306120307120308120309120310120311120312120313120314120315120316120317120318120319120320120321120322120323120324120325120326120327120328120329120330120331120332120333120334120335120336120337120338120339120340120341120342120343120344120345120346120347120348120349120350120351120352120353120354120355120356120357120358120359120360120361120362120363120364120365120366120367120368120369120370120371120372120373120374120375120376120377120378120379120380120381120382120383120384120385120386120387120388120389120390120391120392120393120394120395120396120397120398120399120400120401120402120403120404120405120406120407120408120409120410120411120412120413120414120415120416120417120418120419120420120421120422120423120424120425120426120427120428120429120430120431120432120433120434120435120436120437120438120439120440120441120442120443120444120445120446120447120448120449120450120451120452120453120454120455120456120457120458120459120460120461120462120463120464120465120466120467120468120469120470120471120472120473120474120475120476120477120478120479120480120481120482120483120484120485120486120487120488120489120490120491120492120493120494120495120496120497120498120499120500120501120502120503120504120505120506120507120508120509120510120511120512120513120514120515120516120517120518120519120520120521120522120523120524120525120526120527120528120529120530120531120532120533120534120535120536120537120538120539120540120541120542120543120544120545120546120547120548120549120550120551120552120553120554120555120556120557120558120559120560120561120562120563120564120565120566120567120568120569120570120571120572120573120574120575120576120577120578120579120580120581120582120583120584120585120586120587120588120589120590120591120592120593120594120595120596120597120598120599120600120601120602120603120604120605120606120607120608120609120610120611120612120613120614120615120616120617120618120619120620120621120622120623120624120625120626120627120628120629120630120631120632120633120634120635120636120637120638120639120640120641120642120643120644120645120646120647120648120649120650120651120652120653120654120655120656120657120658120659120660120661120662120663120664120665120666120667120668120669120670120671120672120673120674120675120676120677120678120679120680120681120682120683120684120685120686120687120688120689120690120691120692120693120694120695120696120697120698120699120700120701120702120703120704120705120706120707120708120709120710120711120712120713120714120715120716120717120718120719120720120721120722120723120724120725120726120727120728120729120730120731120732120733120734120735120736120737120738120739120740120741120742120743120744120745120746120747120748120749120750120751120752120753120754120755120756120757120758120759120760120761120762120763120764120765120766120767120768120769120770120771120772120773120774120775120776120777120778120779120780120781120782120783120784120785120786120787120788120789120790120791120792120793120794120795120796120797120798120799120800120801120802120803120804120805120806120807120808120809120810120811120812120813120814120815120816120817120818120819120820120821120822120823120824120825120826120827120828120829120830120831120832120833120834120835120836120837120838120839120840120841120842120843120844120845120846120847120848120849120850120851120852120853120854120855120856120857120858120859120860120861120862120863120864120865120866120867120868120869120870120871120872120873120874120875120876120877120878120879120880120881120882120883120884120885120886120887120888120889120890120891120892120893120894120895120896120897120898120899120900120901120902120903120904120905120906120907120908120909120910120911120912120913120914120915120916120917120918120919120920120921120922120923120924120925120926120927120928120929120930120931120932120933120934120935120936120937120938120939120940120941120942120943120944120945120946120947120948120949120950120951120952120953120954120955120956120957120958120959120960120961120962120963120964120965120966120967120968120969120970120971120972120973120974120975120976120977120978120979120980120981120982120983120984120985120986120987120988120989120990120991120992120993120994120995120996120997120998120999121000121001121002121003121004121005121006121007121008121009121010121011121012121013121014121015121016121017121018121019121020121021121022121023121024121025121026121027121028121029121030121031121032121033121034121035121036121037121038121039121040121041121042121043121044121045121046121047121048121049121050121051121052121053121054121055121056121057121058121059121060121061121062121063121064121065121066121067121068121069121070121071121072121073121074121075121076121077121078121079121080121081121082121083121084121085121086121087121088121089121090121091121092121093121094121095121096121097121098121099121100121101121102121103121104121105121106121107121108121109121110121111121112121113121114121115121116121117121118121119121120121121121122121123121124121125121126121127121128121129121130121131121132121133121134121135121136121137121138121139121140121141121142121143121144121145121146121147121148121149121150121151121152121153121154121155121156121157121158121159121160121161121162121163121164121165121166121167121168121169121170121171121172121173121174121175121176121177121178121179121180121181121182121183121184121185121186121187121188121189121190121191121192121193121194121195121196121197121198121199121200121201121202121203121204121205121206121207121208121209121210121211121212121213121214121215121216121217121218121219121220121221121222121223121224121225121226121227121228121229121230121231121232121233121234121235121236121237121238121239121240121241121242121243121244121245121246121247121248121249121250121251121252121253121254121255121256121257121258121259121260121261121262121263121264121265121266121267121268121269121270121271121272121273121274121275121276121277121278121279121280121281121282121283121284121285121286121287121288121289121290121291121292121293121294121295121296121297121298121299121300121301121302121303121304121305121306121307121308121309121310121311121312121313121314121315121316121317121318121319121320121321121322121323121324121325121326121327121328121329121330121331121332121333121334121335121336121337121338121339121340121341121342121343121344121345121346121347121348121349121350121351121352121353121354121355121356121357121358121359121360121361121362121363121364121365121366121367121368121369121370121371121372121373121374121375121376121377121378121379121380121381121382121383121384121385121386121387121388121389121390121391121392121393121394121395121396121397121398121399121400121401121402121403121404121405121406121407121408121409121410121411121412121413121414121415121416121417121418121419121420121421121422121423121424121425121426121427121428121429121430121431121432121433121434121435121436121437121438121439121440121441121442121443121444121445121446121447121448121449121450121451121452121453121454121455121456121457121458121459121460121461121462121463121464121465121466121467121468121469121470121471121472121473121474121475121476121477121478121479121480121481121482121483121484121485121486121487121488121489121490121491121492121493121494121495121496121497121498121499121500121501121502121503121504121505121506121507121508121509121510121511121512121513121514121515121516121517121518121519121520121521121522121523121524121525121526121527121528121529121530121531121532121533121534121535121536121537121538121539121540121541121542121543121544121545121546121547121548121549121550121551121552121553121554121555121556121557121558121559121560121561121562121563121564121565121566121567121568121569121570121571121572121573121574121575121576121577121578121579121580121581121582121583121584121585121586121587121588121589121590121591121592121593121594121595121596121597121598121599121600121601121602121603121604121605121606121607121608121609121610121611121612121613121614121615121616121617121618121619121620121621121622121623121624121625121626121627121628121629121630121631121632121633121634121635121636121637121638121639121640121641121642121643121644121645121646121647121648121649121650121651121652121653121654121655121656121657121658121659121660121661121662121663121664121665121666121667121668121669121670121671121672121673121674121675121676121677121678121679121680121681121682121683121684121685121686121687121688121689121690121691121692121693121694121695121696121697121698121699121700121701121702121703121704121705121706121707121708121709121710121711121712121713121714121715121716121717121718121719121720121721121722121723121724121725121726121727121728121729121730121731121732121733121734121735121736121737121738121739121740121741121742121743121744121745121746121747121748121749121750121751121752121753121754121755121756121757121758121759121760121761121762121763121764121765121766121767121768121769121770121771121772121773121774121775121776121777121778121779121780121781121782121783121784121785121786121787121788121789121790121791121792121793121794121795121796121797121798121799121800121801121802121803121804121805121806121807121808121809121810121811121812121813121814121815121816121817121818121819121820121821121822121823121824121825121826121827121828121829121830121831121832121833121834121835121836121837121838121839121840121841121842121843121844121845121846121847121848121849121850121851121852121853121854121855121856121857121858121859121860121861121862121863121864121865121866121867121868121869121870121871121872121873121874121875121876121877121878121879121880121881121882121883121884121885121886121887121888121889121890121891121892121893121894121895121896121897121898121899121900121901121902121903121904121905121906121907121908121909121910121911121912121913121914121915121916121917121918121919121920121921121922121923121924121925121926121927121928121929121930121931121932121933121934121935121936121937121938121939121940121941121942121943121944121945121946121947121948121949121950121951121952121953121954121955121956121957121958121959121960121961121962121963121964121965121966121967121968121969121970121971121972121973121974121975121976121977121978121979121980121981121982121983121984121985121986121987121988121989121990121991121992121993121994121995121996121997121998121999122000122001122002122003122004122005122006122007122008122009122010122011122012122013122014122015122016122017122018122019122020122021122022122023122024122025122026122027122028122029122030122031122032122033122034122035122036122037122038122039122040122041122042122043122044122045122046122047122048122049122050122051122052122053122054122055122056122057122058122059122060122061122062122063122064122065122066122067122068122069122070122071122072122073122074122075122076122077122078122079122080122081122082122083122084122085122086122087122088122089122090122091122092122093122094122095122096122097122098122099122100122101122102122103122104122105122106122107122108122109122110122111122112122113122114122115122116122117122118122119122120122121122122122123122124122125122126122127122128122129122130122131122132122133122134122135122136122137122138122139122140122141122142122143122144122145122146122147122148122149122150122151122152122153122154122155122156122157122158122159122160122161122162122163122164122165122166122167122168122169122170122171122172122173122174122175122176122177122178122179122180122181122182122183122184122185122186122187122188122189122190122191122192122193122194122195122196122197122198122199122200122201122202122203122204122205122206122207122208122209122210122211122212122213122214122215122216122217122218122219122220122221122222122223122224122225122226122227122228122229122230122231122232122233122234122235122236122237122238122239122240122241122242122243122244122245122246122247122248122249122250122251122252122253122254122255122256122257122258122259122260122261122262122263122264122265122266122267122268122269122270122271122272122273122274122275122276122277122278122279122280122281122282122283122284122285122286122287122288122289122290122291122292122293122294122295122296122297122298122299122300122301122302122303122304122305122306122307122308122309122310122311122312122313122314122315122316122317122318122319122320122321122322122323122324122325122326122327122328122329122330122331122332122333122334122335122336122337122338122339122340122341122342122343122344122345122346122347122348122349122350122351122352122353122354122355122356122357122358122359122360122361122362122363122364122365122366122367122368122369122370122371122372122373122374122375122376122377122378122379122380122381122382122383122384122385122386122387122388122389122390122391122392122393122394122395122396122397122398122399122400122401122402122403122404122405122406122407122408122409122410122411122412122413122414122415122416122417122418122419122420122421122422122423122424122425122426122427122428122429122430122431122432122433122434122435122436122437122438122439122440122441122442122443122444122445122446122447122448122449122450122451122452122453122454122455122456122457122458122459122460122461122462122463122464122465122466122467122468122469122470122471122472122473122474122475122476122477122478122479122480122481122482122483122484122485122486122487122488122489122490122491122492122493122494122495122496122497122498122499122500122501122502122503122504122505122506122507122508122509122510122511122512122513122514122515122516122517122518122519122520122521122522122523122524122525122526122527122528122529122530122531122532122533122534122535122536122537122538122539122540122541122542122543122544122545122546122547122548122549122550122551122552122553122554122555122556122557122558122559122560122561122562122563122564122565122566122567122568122569122570122571122572122573122574122575122576122577122578122579122580122581122582122583122584122585122586122587122588122589122590122591122592122593122594122595122596122597122598122599122600122601122602122603122604122605122606122607122608122609122610122611122612122613122614122615122616122617122618122619122620122621122622122623122624122625122626122627122628122629122630122631122632122633122634122635122636122637122638122639122640122641122642122643122644122645122646122647122648122649122650122651122652122653122654122655122656122657122658122659122660122661122662122663122664122665122666122667122668122669122670122671122672122673122674122675122676122677122678122679122680122681122682122683122684122685122686122687122688122689122690122691122692122693122694122695122696122697122698122699122700122701122702122703122704122705122706122707122708122709122710122711122712122713122714122715122716122717122718122719122720122721122722122723122724122725122726122727122728122729122730122731122732122733122734122735122736122737122738122739122740122741122742122743122744122745122746122747122748122749122750122751122752122753122754122755122756122757122758122759122760122761122762122763122764122765122766122767122768122769122770122771122772122773122774122775122776122777122778122779122780122781122782122783122784122785122786122787122788122789122790122791122792122793122794122795122796122797122798122799122800122801122802122803122804122805122806122807122808122809122810122811122812122813122814122815122816122817122818122819122820122821122822122823122824122825122826122827122828122829122830122831122832122833122834122835122836122837122838122839122840122841122842122843122844122845122846122847122848122849122850122851122852122853122854122855122856122857122858122859122860122861122862122863122864122865122866122867122868122869122870122871122872122873122874122875122876122877122878122879122880122881122882122883122884122885122886122887122888122889122890122891122892122893122894122895122896122897122898122899122900122901122902122903122904122905122906122907122908122909122910122911122912122913122914122915122916122917122918122919122920122921122922122923122924122925122926122927122928122929122930122931122932122933122934122935122936122937122938122939122940122941122942122943122944122945122946122947122948122949122950122951122952122953122954122955122956122957122958122959122960122961122962122963122964122965122966122967122968122969122970122971122972122973122974122975122976122977122978122979122980122981122982122983122984122985122986122987122988122989122990122991122992122993122994122995122996122997122998122999123000123001123002123003123004123005123006123007123008123009123010123011123012123013123014123015123016123017123018123019123020123021123022123023123024123025123026123027123028123029123030123031123032123033123034123035123036123037123038123039123040123041123042123043123044123045123046123047123048123049123050123051123052123053123054123055123056123057123058123059123060123061123062123063123064123065123066123067123068123069123070123071123072123073123074123075123076123077123078123079123080123081123082123083123084123085123086123087123088123089123090123091123092123093123094123095123096123097123098123099123100123101123102123103123104123105123106123107123108123109123110123111123112123113123114123115123116123117123118123119123120123121123122123123123124123125123126123127123128123129123130123131123132123133123134123135123136123137123138123139123140123141123142123143123144123145123146123147123148123149123150123151123152123153123154123155123156123157123158123159123160123161123162123163123164123165123166123167123168123169123170123171123172123173123174123175123176123177123178123179123180123181123182123183123184123185123186123187123188123189123190123191123192123193123194123195123196123197123198123199123200123201123202123203123204123205123206123207123208123209123210123211123212123213123214123215123216123217123218123219123220123221123222123223123224123225123226123227123228123229123230123231123232123233123234123235123236123237123238123239123240123241123242123243123244123245123246123247123248123249123250123251123252123253123254123255123256123257123258123259123260123261123262123263123264123265123266123267123268123269123270123271123272123273123274123275123276123277123278123279123280123281123282123283123284123285123286123287123288123289123290123291123292123293123294123295123296123297123298123299123300123301123302123303123304123305123306123307123308123309123310123311123312123313123314123315123316123317123318123319123320123321123322123323123324123325123326123327123328123329123330123331123332123333123334123335123336123337123338123339123340123341123342123343123344123345123346123347123348123349123350123351123352123353123354123355123356123357123358123359123360123361123362123363123364123365123366123367123368123369123370123371123372123373123374123375123376123377123378123379123380123381123382123383123384123385123386123387123388123389123390123391123392123393123394123395123396123397123398123399123400123401123402123403123404123405123406123407123408123409123410123411123412123413123414123415123416123417123418123419123420123421123422123423123424123425123426123427123428123429123430123431123432123433123434123435123436123437123438123439123440123441123442123443123444123445123446123447123448123449123450123451123452123453123454123455123456123457123458123459123460123461123462123463123464123465123466123467123468123469123470123471123472123473123474123475123476123477123478123479123480123481123482123483123484123485123486123487123488123489123490123491123492123493123494123495123496123497123498123499123500123501123502123503123504123505123506123507123508123509123510123511123512123513123514123515123516123517123518123519123520123521123522123523123524123525123526123527123528123529123530123531123532123533123534123535123536123537123538123539123540123541123542123543123544123545123546123547123548123549123550123551123552123553123554123555123556123557123558123559123560123561123562123563123564123565123566123567123568123569123570123571123572123573123574123575123576123577123578123579123580123581123582123583123584123585123586123587123588123589123590123591123592123593123594123595123596123597123598123599123600123601123602123603123604123605123606123607123608123609123610123611123612123613123614123615123616123617123618123619123620123621123622123623123624123625123626123627123628123629123630123631123632123633123634123635123636123637123638123639123640123641123642123643123644123645123646123647123648123649123650123651123652123653123654123655123656123657123658123659123660123661123662123663123664123665123666123667123668123669123670123671123672123673123674123675123676123677123678123679123680123681123682123683123684123685123686123687123688123689123690123691123692123693123694123695123696123697123698123699123700123701123702123703123704123705123706123707123708123709123710123711123712123713123714123715123716123717123718123719123720123721123722123723123724123725123726123727123728123729123730123731123732123733123734123735123736123737123738123739123740123741123742123743123744123745123746123747123748123749123750123751123752123753123754123755123756123757123758123759123760123761123762123763123764123765123766123767123768123769123770123771123772123773123774123775123776123777123778123779123780123781123782123783123784123785123786123787123788123789123790123791123792123793123794123795123796123797123798123799123800123801123802123803123804123805123806123807123808123809123810123811123812123813123814123815123816123817123818123819123820123821123822123823123824123825123826123827123828123829123830123831123832123833123834123835123836123837123838123839123840123841123842123843123844123845123846123847123848123849123850123851123852123853123854123855123856123857123858123859123860123861123862123863123864123865123866123867123868123869123870123871123872123873123874123875123876123877123878123879123880123881123882123883123884123885123886123887123888123889123890123891123892123893123894123895123896123897123898123899123900123901123902123903123904123905123906123907123908123909123910123911123912123913123914123915123916123917123918123919123920123921123922123923123924123925123926123927123928123929123930123931123932123933123934123935123936123937123938123939123940123941123942123943123944123945123946123947123948123949123950123951123952123953123954123955123956123957123958123959123960123961123962123963123964123965123966123967123968123969123970123971123972123973123974123975123976123977123978123979123980123981123982123983123984123985123986123987123988123989123990123991123992123993123994123995123996123997123998123999124000124001124002124003124004124005124006124007124008124009124010124011124012124013124014124015124016124017124018124019124020124021124022124023124024124025124026124027124028124029124030124031124032124033124034124035124036124037124038124039124040124041124042124043124044124045124046124047124048124049124050124051124052124053124054124055124056124057124058124059124060124061124062124063124064124065124066124067124068124069124070124071124072124073124074124075124076124077124078124079124080124081124082124083124084124085124086124087124088124089124090124091124092124093124094124095124096124097124098124099124100124101124102124103124104124105124106124107124108124109124110124111124112124113124114124115124116124117124118124119124120124121124122124123124124124125124126124127124128124129124130124131124132124133124134124135124136124137124138124139124140124141124142124143124144124145124146124147124148124149124150124151124152124153124154124155124156124157124158124159124160124161124162124163124164124165124166124167124168124169124170124171124172124173124174124175124176124177124178124179124180124181124182124183124184124185124186124187124188124189124190124191124192124193124194124195124196124197124198124199124200124201124202124203124204124205124206124207124208124209124210124211124212124213124214124215124216124217124218124219124220124221124222124223124224124225124226124227124228124229124230124231124232124233124234124235124236124237124238124239124240124241124242124243124244124245124246124247124248124249124250124251124252124253124254124255124256124257124258124259124260124261124262124263124264124265124266124267124268124269124270124271124272124273124274124275124276124277124278124279124280124281124282124283124284124285124286124287124288124289124290124291124292124293124294124295124296124297124298124299124300124301124302124303124304124305124306124307124308124309124310124311124312124313124314124315124316124317124318124319124320124321124322124323124324124325124326124327124328124329124330124331124332124333124334124335124336124337124338124339124340124341124342124343124344124345124346124347124348124349124350124351124352124353124354124355124356124357124358124359124360124361124362124363124364124365124366124367124368124369124370124371124372124373124374124375124376124377124378124379124380124381124382124383124384124385124386124387124388124389124390124391124392124393124394124395124396124397124398124399124400124401124402124403124404124405124406124407124408124409124410124411124412124413124414124415124416124417124418124419124420124421124422124423124424124425124426124427124428124429124430124431124432124433124434124435124436124437124438124439124440124441124442124443124444124445124446124447124448124449124450124451124452124453124454124455124456124457124458124459124460124461124462124463124464124465124466124467124468124469124470124471124472124473124474124475124476124477124478124479124480124481124482124483124484124485124486124487124488124489124490124491124492124493124494124495124496124497124498124499124500124501124502124503124504124505124506124507124508124509124510124511124512124513124514124515124516124517124518124519124520124521124522124523124524124525124526124527124528124529124530124531124532124533124534124535124536124537124538124539124540124541124542124543124544124545124546124547124548124549124550124551124552124553124554124555124556124557124558124559124560124561124562124563124564124565124566124567124568124569124570124571124572124573124574124575124576124577124578124579124580124581124582124583124584124585124586124587124588124589124590124591124592124593124594124595124596124597124598124599124600124601124602124603124604124605124606124607124608124609124610124611124612124613124614124615124616124617124618124619124620124621124622124623124624124625124626124627124628124629124630124631124632124633124634124635124636124637124638124639124640124641124642124643124644124645124646124647124648124649124650124651124652124653124654124655124656124657124658124659124660124661124662124663124664124665124666124667124668124669124670124671124672124673124674124675124676124677124678124679124680124681124682124683124684124685124686124687124688124689124690124691124692124693124694124695124696124697124698124699124700124701124702124703124704124705124706124707124708124709124710124711124712124713124714124715124716124717124718124719124720124721124722124723124724124725124726124727124728124729124730124731124732124733124734124735124736124737124738124739124740124741124742124743124744124745124746124747124748124749124750124751124752124753124754124755124756124757124758124759124760124761124762124763124764124765124766124767124768124769124770124771124772124773124774124775124776124777124778124779124780124781124782124783124784124785124786124787124788124789124790124791124792124793124794124795124796124797124798124799124800124801124802124803124804124805124806124807124808124809124810124811124812124813124814124815124816124817124818124819124820124821124822124823124824124825124826124827124828124829124830124831124832124833124834124835124836124837124838124839124840124841124842124843124844124845124846124847124848124849124850124851124852124853124854124855124856124857124858124859124860124861124862124863124864124865124866124867124868124869124870124871124872124873124874124875124876124877124878124879124880124881124882124883124884124885124886124887124888124889124890124891124892124893124894124895124896124897124898124899124900124901124902124903124904124905124906124907124908124909124910124911124912124913124914124915124916124917124918124919124920124921124922124923124924124925124926124927124928124929124930124931124932124933124934124935124936124937124938124939124940124941124942124943124944124945124946124947124948124949124950124951124952124953124954124955124956124957124958124959124960124961124962124963124964124965124966124967124968124969124970124971124972124973124974124975124976124977124978124979124980124981124982124983124984124985124986124987124988124989124990124991124992124993124994124995124996124997124998124999125000125001125002125003125004125005125006125007125008125009125010125011125012125013125014125015125016125017125018125019125020125021125022125023125024125025125026125027125028125029125030125031125032125033125034125035125036125037125038125039125040125041125042125043125044125045125046125047125048125049125050125051125052125053125054125055125056125057125058125059125060125061125062125063125064125065125066125067125068125069125070125071125072125073125074125075125076125077125078125079125080125081125082125083125084125085125086125087125088125089125090125091125092125093125094125095125096125097125098125099125100125101125102125103125104125105125106125107125108125109125110125111125112125113125114125115125116125117125118125119125120125121125122125123125124125125125126125127125128125129125130125131125132125133125134125135125136125137125138125139125140125141125142125143125144125145125146125147125148125149125150125151125152125153125154125155125156125157125158125159125160125161125162125163125164125165125166125167125168125169125170125171125172125173125174125175125176125177125178125179125180125181125182125183125184125185125186125187125188125189125190125191125192125193125194125195125196125197125198125199125200125201125202125203125204125205125206125207125208125209125210125211125212125213125214125215125216125217125218125219125220125221125222125223125224125225125226125227125228125229125230125231125232125233125234125235125236125237125238125239125240125241125242125243125244125245125246125247125248125249125250125251125252125253125254125255125256125257125258125259125260125261125262125263125264125265125266125267125268125269125270125271125272125273125274125275125276125277125278125279125280125281125282125283125284125285125286125287125288125289125290125291125292125293125294125295125296125297125298125299125300125301125302125303125304125305125306125307125308125309125310125311125312125313125314125315125316125317125318125319125320125321125322125323125324125325125326125327125328125329125330125331125332125333125334125335125336125337125338125339125340125341125342125343125344125345125346125347125348125349125350125351125352125353125354125355125356125357125358125359125360125361125362125363125364125365125366125367125368125369125370125371125372125373125374125375125376125377125378125379125380125381125382125383125384125385125386125387125388125389125390125391125392125393125394125395125396125397125398125399125400125401125402125403125404125405125406125407125408125409125410125411125412125413125414125415125416125417125418125419125420125421125422125423125424125425125426125427125428125429125430125431125432125433125434125435125436125437125438125439125440125441125442125443125444125445125446125447125448125449125450125451125452125453125454125455125456125457125458125459125460125461125462125463125464125465125466125467125468125469125470125471125472125473125474125475125476125477125478125479125480125481125482125483125484125485125486125487125488125489125490125491125492125493125494125495125496125497125498125499125500125501125502125503125504125505125506125507125508125509125510125511125512125513125514125515125516125517125518125519125520125521125522125523125524125525125526125527125528125529125530125531125532125533125534125535125536125537125538125539125540125541125542125543125544125545125546125547125548125549125550125551125552125553125554125555125556125557125558125559125560125561125562125563125564125565125566125567125568125569125570125571125572125573125574125575125576125577125578125579125580125581125582125583125584125585125586125587125588125589125590125591125592125593125594125595125596125597125598125599125600125601125602125603125604125605125606125607125608125609125610125611125612125613125614125615125616125617125618125619125620125621125622125623125624125625125626125627125628125629125630125631125632125633125634125635125636125637125638125639125640125641125642125643125644125645125646125647125648125649125650125651125652125653125654125655125656125657125658125659125660125661125662125663125664125665125666125667125668125669125670125671125672125673125674125675125676125677125678125679125680125681125682125683125684125685125686125687125688125689125690125691125692125693125694125695125696125697125698125699125700125701125702125703125704125705125706125707125708125709125710125711125712125713125714125715125716125717125718125719125720125721125722125723125724125725125726125727125728125729125730125731125732125733125734125735125736125737125738125739125740125741125742125743125744125745125746125747125748125749125750125751125752125753125754125755125756125757125758125759125760125761125762125763125764125765125766125767125768125769125770125771125772125773125774125775125776125777125778125779125780125781125782125783125784125785125786125787125788125789125790125791125792125793125794125795125796125797125798125799125800125801125802125803125804125805125806125807125808125809125810125811125812125813125814125815125816125817125818125819125820125821125822125823125824125825125826125827125828125829125830125831125832125833125834125835125836125837125838125839125840125841125842125843125844125845125846125847125848125849125850125851125852125853125854125855125856125857125858125859125860125861125862125863125864125865125866125867125868125869125870125871125872125873125874125875125876125877125878125879125880125881125882125883125884125885125886125887125888125889125890125891125892125893125894125895125896125897125898125899125900125901125902125903125904125905125906125907125908125909125910125911125912125913125914125915125916125917125918125919125920125921125922125923125924125925125926125927125928125929125930125931125932125933125934125935125936125937125938125939125940125941125942125943125944125945125946125947125948125949125950125951125952125953125954125955125956125957125958125959125960125961125962125963125964125965125966125967125968125969125970125971125972125973125974125975125976125977125978125979125980125981125982125983125984125985125986125987125988125989125990125991125992125993125994125995125996125997125998125999126000126001126002126003126004126005126006126007126008126009126010126011126012126013126014126015126016126017126018126019126020126021126022126023126024126025126026126027126028126029126030126031126032126033126034126035126036126037126038126039126040126041126042126043126044126045126046126047126048126049126050126051126052126053126054126055126056126057126058126059126060126061126062126063126064126065126066126067126068126069126070126071126072126073126074126075126076126077126078126079126080126081126082126083126084126085126086126087126088126089126090126091126092126093126094126095126096126097126098126099126100126101126102126103126104126105126106126107126108126109126110126111126112126113126114126115126116126117126118126119126120126121126122126123126124126125126126126127126128126129126130126131126132126133126134126135126136126137126138126139126140126141126142126143126144126145126146126147126148126149126150126151126152126153126154126155126156126157126158126159126160126161126162126163126164126165126166126167126168126169126170126171126172126173126174126175126176126177126178126179126180126181126182126183126184126185126186126187126188126189126190126191126192126193126194126195126196126197126198126199126200126201126202126203126204126205126206126207126208126209126210126211126212126213126214126215126216126217126218126219126220126221126222126223126224126225126226126227126228126229126230126231126232126233126234126235126236126237126238126239126240126241126242126243126244126245126246126247126248126249126250126251126252126253126254126255126256126257126258126259126260126261126262126263126264126265126266126267126268126269126270126271126272126273126274126275126276126277126278126279126280126281126282126283126284126285126286126287126288126289126290126291126292126293126294126295126296126297126298126299126300126301126302126303126304126305126306126307126308126309126310126311126312126313126314126315126316126317126318126319126320126321126322126323126324126325126326126327126328126329126330126331126332126333126334126335126336126337126338126339126340126341126342126343126344126345126346126347126348126349126350126351126352126353126354126355126356126357126358126359126360126361126362126363126364126365126366126367126368126369126370126371126372126373126374126375126376126377126378126379126380126381126382126383126384126385126386126387126388126389126390126391126392126393126394126395126396126397126398126399126400126401126402126403126404126405126406126407126408126409126410126411126412126413126414126415126416126417126418126419126420126421126422126423126424126425126426126427126428126429126430126431126432126433126434126435126436126437126438126439126440126441126442126443126444126445126446126447126448126449126450126451126452126453126454126455126456126457126458126459126460126461126462126463126464126465126466126467126468126469126470126471126472126473126474126475126476126477126478126479126480126481126482126483126484126485126486126487126488126489126490126491126492126493126494126495126496126497126498126499126500126501126502126503126504126505126506126507126508126509126510126511126512126513126514126515126516126517126518126519126520126521126522126523126524126525126526126527126528126529126530126531126532126533126534126535126536126537126538126539126540126541126542126543126544126545126546126547126548126549126550126551126552126553126554126555126556126557126558126559126560126561126562126563126564126565126566126567126568126569126570126571126572126573126574126575126576126577126578126579126580126581126582126583126584126585126586126587126588126589126590126591126592126593126594126595126596126597126598126599126600126601126602126603126604126605126606126607126608126609126610126611126612126613126614126615126616126617126618126619126620126621126622126623126624126625126626126627126628126629126630126631126632126633126634126635126636126637126638126639126640126641126642126643126644126645126646126647126648126649126650126651126652126653126654126655126656126657126658126659126660126661126662126663126664126665126666126667126668126669126670126671126672126673126674126675126676126677126678126679126680126681126682126683126684126685126686126687126688126689126690126691126692126693126694126695126696126697126698126699126700126701126702126703126704126705126706126707126708126709126710126711126712126713126714126715126716126717126718126719126720126721126722126723126724126725126726126727126728126729126730126731126732126733126734126735126736126737126738126739126740126741126742126743126744126745126746126747126748126749126750126751126752126753126754126755126756126757126758126759126760126761126762126763126764126765126766126767126768126769126770126771126772126773126774126775126776126777126778126779126780126781126782126783126784126785126786126787126788126789126790126791126792126793126794126795126796126797126798126799126800126801126802126803126804126805126806126807126808126809126810126811126812126813126814126815126816126817126818126819126820126821126822126823126824126825126826126827126828126829126830126831126832126833126834126835126836126837126838126839126840126841126842126843126844126845126846126847126848126849126850126851126852126853126854126855126856126857126858126859126860126861126862126863126864126865126866126867126868126869126870126871126872126873126874126875126876126877126878126879126880126881126882126883126884126885126886126887126888126889126890126891126892126893126894126895126896126897126898126899126900126901126902126903126904126905126906126907126908126909126910126911126912126913126914126915126916126917126918126919126920126921126922126923126924126925126926126927126928126929126930126931126932126933126934126935126936126937126938126939126940126941126942126943126944126945126946126947126948126949126950126951126952126953126954126955126956126957126958126959126960126961126962126963126964126965126966126967126968126969126970126971126972126973126974126975126976126977126978126979126980126981126982126983126984126985126986126987126988126989126990126991126992126993126994126995126996126997126998126999127000127001127002127003127004127005127006127007127008127009127010127011127012127013127014127015127016127017127018127019127020127021127022127023127024127025127026127027127028127029127030127031127032127033127034127035127036127037127038127039127040127041127042127043127044127045127046127047127048127049127050127051127052127053127054127055127056127057127058127059127060127061127062127063127064127065127066127067127068127069127070127071127072127073127074127075127076127077127078127079127080127081127082127083127084127085127086127087127088127089127090127091127092127093127094127095127096127097127098127099127100127101127102127103127104127105127106127107127108127109127110127111127112127113127114127115127116127117127118127119127120127121127122127123127124127125127126127127127128127129127130127131127132127133127134127135127136127137127138127139127140127141127142127143127144127145127146127147127148127149127150127151127152127153127154127155127156127157127158127159127160127161127162127163127164127165127166127167127168127169127170127171127172127173127174127175127176127177127178127179127180127181127182127183127184127185127186127187127188127189127190127191127192127193127194127195127196127197127198127199127200127201127202127203127204127205127206127207127208127209127210127211127212127213127214127215127216127217127218127219127220127221127222127223127224127225127226127227127228127229127230127231127232127233127234127235127236127237127238127239127240127241127242127243127244127245127246127247127248127249127250127251127252127253127254127255127256127257127258127259127260127261127262127263127264127265127266127267127268127269127270127271127272127273127274127275127276127277127278127279127280127281127282127283127284127285127286127287127288127289127290127291127292127293127294127295127296127297127298127299127300127301127302127303127304127305127306127307127308127309127310127311127312127313127314127315127316127317127318127319127320127321127322127323127324127325127326127327127328127329127330127331127332127333127334127335127336127337127338127339127340127341127342127343127344127345127346127347127348127349127350127351127352127353127354127355127356127357127358127359127360127361127362127363127364127365127366127367127368127369127370127371127372127373127374127375127376127377127378127379127380127381127382127383127384127385127386127387127388127389127390127391127392127393127394127395127396127397127398127399127400127401127402127403127404127405127406127407127408127409127410127411127412127413127414127415127416127417127418127419127420127421127422127423127424127425127426127427127428127429127430127431127432127433127434127435127436127437127438127439127440127441127442127443127444127445127446127447127448127449127450127451127452127453127454127455127456127457127458127459127460127461127462127463127464127465127466127467127468127469127470127471127472127473127474127475127476127477127478127479127480127481127482127483127484127485127486127487127488127489127490127491127492127493127494127495127496127497127498127499127500127501127502127503127504127505127506127507127508127509127510127511127512127513127514127515127516127517127518127519127520127521127522127523127524127525127526127527127528127529127530127531127532127533127534127535127536127537127538127539127540127541127542127543127544127545127546127547127548127549127550127551127552127553127554127555127556127557127558127559127560127561127562127563127564127565127566127567127568127569127570127571127572127573127574127575127576127577127578127579127580127581127582127583127584127585127586127587127588127589127590127591127592127593127594127595127596127597127598127599127600127601127602127603127604127605127606127607127608127609127610127611127612127613127614127615127616127617127618127619127620127621127622127623127624127625127626127627127628127629127630127631127632127633127634127635127636127637127638127639127640127641127642127643127644127645127646127647127648127649127650127651127652127653127654127655127656127657127658127659127660127661127662127663127664127665127666127667127668127669127670127671127672127673127674127675127676127677127678127679127680127681127682127683127684127685127686127687127688127689127690127691127692127693127694127695127696127697127698127699127700127701127702127703127704127705127706127707127708127709127710127711127712127713127714127715127716127717127718127719127720127721127722127723127724127725127726127727127728127729127730127731127732127733127734127735127736127737127738127739127740127741127742127743127744127745127746127747127748127749127750127751127752127753127754127755127756127757127758127759127760127761127762127763127764127765127766127767127768127769127770127771127772127773127774127775127776127777127778127779127780127781127782127783127784127785127786127787127788127789127790127791127792127793127794127795127796127797127798127799127800127801127802127803127804127805127806127807127808127809127810127811127812127813127814127815127816127817127818127819127820127821127822127823127824127825127826127827127828127829127830127831127832127833127834127835127836127837127838127839127840127841127842127843127844127845127846127847127848127849127850127851127852127853127854127855127856127857127858127859127860127861127862127863127864127865127866127867127868127869127870127871127872127873127874127875127876127877127878127879127880127881127882127883127884127885127886127887127888127889127890127891127892127893127894127895127896127897127898127899127900127901127902127903127904127905127906127907127908127909127910127911127912127913127914127915127916127917127918127919127920127921127922127923127924127925127926127927127928127929127930127931127932127933127934127935127936127937127938127939127940127941127942127943127944127945127946127947127948127949127950127951127952127953127954127955127956127957127958127959127960127961127962127963127964127965127966127967127968127969127970127971127972127973127974127975127976127977127978127979127980127981127982127983127984127985127986127987127988127989127990127991127992127993127994127995127996127997127998127999128000128001128002128003128004128005128006128007128008128009128010128011128012128013128014128015128016128017128018128019128020128021128022128023128024128025128026128027128028128029128030128031128032128033128034128035128036128037128038128039128040128041128042128043128044128045128046128047128048128049128050128051128052128053128054128055128056128057128058128059128060128061128062128063128064128065128066128067128068128069128070128071128072128073128074128075128076128077128078128079128080128081128082128083128084128085128086128087128088128089128090128091128092128093128094128095128096128097128098128099128100128101128102128103128104128105128106128107128108128109128110128111128112128113128114128115128116128117128118128119128120128121128122128123128124128125128126128127128128128129128130128131128132128133128134128135128136128137128138128139128140128141128142128143128144128145128146128147128148128149128150128151128152128153128154128155128156128157128158128159128160128161128162128163128164128165128166128167128168128169128170128171128172128173128174128175128176128177128178128179128180128181128182128183128184128185128186128187128188128189128190128191128192128193128194128195128196128197128198128199128200128201128202128203128204128205128206128207128208128209128210128211128212128213128214128215128216128217128218128219128220128221128222128223128224128225128226128227128228128229128230128231128232128233128234128235128236128237128238128239128240128241128242128243128244128245128246128247128248128249128250128251128252128253128254128255128256128257128258128259128260128261128262128263128264128265128266128267128268128269128270128271128272128273128274128275128276128277128278128279128280128281128282128283128284128285128286128287128288128289128290128291128292128293128294128295128296128297128298128299128300128301128302128303128304128305128306128307128308128309128310128311128312128313128314128315128316128317128318128319128320128321128322128323128324128325128326128327128328128329128330128331128332128333128334128335128336128337128338128339128340128341128342128343128344128345128346128347128348128349128350128351128352128353128354128355128356128357128358128359128360128361128362128363128364128365128366128367128368128369128370128371128372128373128374128375128376128377128378128379128380128381128382128383128384128385128386128387128388128389128390128391128392128393128394128395128396128397128398128399128400128401128402128403128404128405128406128407128408128409128410128411128412128413128414128415128416128417128418128419128420128421128422128423128424128425128426128427128428128429128430128431128432128433128434128435128436128437128438128439128440128441128442128443128444128445128446128447128448128449128450128451128452128453128454128455128456128457128458128459128460128461128462128463128464128465128466128467128468128469128470128471128472128473128474128475128476128477128478128479128480128481128482128483128484128485128486128487128488128489128490128491128492128493128494128495128496128497128498128499128500128501128502128503128504128505128506128507128508128509128510128511128512128513128514128515128516128517128518128519128520128521128522128523128524128525128526128527128528128529128530128531128532128533128534128535128536128537128538128539128540128541128542128543128544128545128546128547128548128549128550128551128552128553128554128555128556128557128558128559128560128561128562128563128564128565128566128567128568128569128570128571128572128573128574128575128576128577128578128579128580128581128582128583128584128585128586128587128588128589128590128591128592128593128594128595128596128597128598128599128600128601128602128603128604128605128606128607128608128609128610128611128612128613128614128615128616128617128618128619128620128621128622128623128624128625128626128627128628128629128630128631128632128633128634128635128636128637128638128639128640128641128642128643128644128645128646128647128648128649128650128651128652128653128654128655128656128657128658128659128660128661128662128663128664128665128666128667128668128669128670128671128672128673128674128675128676128677128678128679128680128681128682128683128684128685128686128687128688128689128690128691128692128693128694128695128696128697128698128699128700128701128702128703128704128705128706128707128708128709128710128711128712128713128714128715128716128717128718128719128720128721128722128723128724128725128726128727128728128729128730128731128732128733128734128735128736128737128738128739128740128741128742128743128744128745128746128747128748128749128750128751128752128753128754128755128756128757128758128759128760128761128762128763128764128765128766128767128768128769128770128771128772128773128774128775128776128777128778128779128780128781128782128783128784128785128786128787128788128789128790128791128792128793128794128795128796128797128798128799128800128801128802128803128804128805128806128807128808128809128810128811128812128813128814128815128816128817128818128819128820128821128822128823128824128825128826128827128828128829128830128831128832128833128834128835128836128837128838128839128840128841128842128843128844128845128846128847128848128849128850128851128852128853128854128855128856128857128858128859128860128861128862128863128864128865128866128867128868128869128870128871128872128873128874128875128876128877128878128879128880128881128882128883128884128885128886128887128888128889128890128891128892128893128894128895128896128897128898128899128900128901128902128903128904128905128906128907128908128909128910128911128912128913128914128915128916128917128918128919128920128921128922128923128924128925128926128927128928128929128930128931128932128933128934128935128936128937128938128939128940128941128942128943128944128945128946128947128948128949128950128951128952128953128954128955128956128957128958128959128960128961128962128963128964128965128966128967128968128969128970128971128972128973128974128975128976128977128978128979128980128981128982128983128984128985128986128987128988128989128990128991128992128993128994128995128996128997128998128999129000129001129002129003129004129005129006129007129008129009129010129011129012129013129014129015129016129017129018129019129020129021129022129023129024129025129026129027129028129029129030129031129032129033129034129035129036129037129038129039129040129041129042129043129044129045129046129047129048129049129050129051129052129053129054129055129056129057129058129059129060129061129062129063129064129065129066129067129068129069129070129071129072129073129074129075129076129077129078129079129080129081129082129083129084129085129086129087129088129089129090129091129092129093129094129095129096129097129098129099129100129101129102129103129104129105129106129107129108129109129110129111129112129113129114129115129116129117129118129119129120129121129122129123129124129125129126129127129128129129129130129131129132129133129134129135129136129137129138129139129140129141129142129143129144129145129146129147129148129149129150129151129152129153129154129155129156129157129158129159129160129161129162129163129164129165129166129167129168129169129170129171129172129173129174129175129176129177129178129179129180129181129182129183129184129185129186129187129188129189129190129191129192129193129194129195129196129197129198129199129200129201129202129203129204129205129206129207129208129209129210129211129212129213129214129215129216129217129218129219129220129221129222129223129224129225129226129227129228129229129230129231129232129233129234129235129236129237129238129239129240129241129242129243129244129245129246129247129248129249129250129251129252129253129254129255129256129257129258129259129260129261129262129263129264129265129266129267129268129269129270129271129272129273129274129275129276129277129278129279129280129281129282129283129284129285129286129287129288129289129290129291129292129293129294129295129296129297129298129299129300129301129302129303129304129305129306129307129308129309129310129311129312129313129314129315129316129317129318129319129320129321129322129323129324129325129326129327129328129329129330129331129332129333129334129335129336129337129338129339129340129341129342129343129344129345129346129347129348129349129350129351129352129353129354129355129356129357129358129359129360129361129362129363129364129365129366129367129368129369129370129371129372129373129374129375129376129377129378129379129380129381129382129383129384129385129386129387129388129389129390129391129392129393129394129395129396129397129398129399129400129401129402129403129404129405129406129407129408129409129410129411129412129413129414129415129416129417129418129419129420129421129422129423129424129425129426129427129428129429129430129431129432129433129434129435129436129437129438129439129440129441129442129443129444129445129446129447129448129449129450129451129452129453129454129455129456129457129458129459129460129461129462129463129464129465129466129467129468129469129470129471129472129473129474129475129476129477129478129479129480129481129482129483129484129485129486129487129488129489129490129491129492129493129494129495129496129497129498129499129500129501129502129503129504129505129506129507129508129509129510129511129512129513129514129515129516129517129518129519129520129521129522129523129524129525129526129527129528129529129530129531129532129533129534129535129536129537129538129539129540129541129542129543129544129545129546129547129548129549129550129551129552129553129554129555129556129557129558129559129560129561129562129563129564129565129566129567129568129569129570129571129572129573129574129575129576129577129578129579129580129581129582129583129584129585129586129587129588129589129590129591129592129593129594129595129596129597129598129599129600129601129602129603129604129605129606129607129608129609129610129611129612129613129614129615129616129617129618129619129620129621129622129623129624129625129626129627129628129629129630129631129632129633129634129635129636129637129638129639129640129641129642129643129644129645129646129647129648129649129650129651129652129653129654129655129656129657129658129659129660129661129662129663129664129665129666129667129668129669129670129671129672129673129674129675129676129677129678129679129680129681129682129683129684129685129686129687129688129689129690129691129692129693129694129695129696129697129698129699129700129701129702129703129704129705129706129707129708129709129710129711129712129713129714129715129716129717129718129719129720129721129722129723129724129725129726129727129728129729129730129731129732129733129734129735129736129737129738129739129740129741129742129743129744129745129746129747129748129749129750129751129752129753129754129755129756129757129758129759129760129761129762129763129764129765129766129767129768129769129770129771129772129773129774129775129776129777129778129779129780129781129782129783129784129785129786129787129788129789129790129791129792129793129794129795129796129797129798129799129800129801129802129803129804129805129806129807129808129809129810129811129812129813129814129815129816129817129818129819129820129821129822129823129824129825129826129827129828129829129830129831129832129833129834129835129836129837129838129839129840129841129842129843129844129845129846129847129848129849129850129851129852129853129854129855129856129857129858129859129860129861129862129863129864129865129866129867129868129869129870129871129872129873129874129875129876129877129878129879129880129881129882129883129884129885129886129887129888129889129890129891129892129893129894129895129896129897129898129899129900129901129902129903129904129905129906129907129908129909129910129911129912129913129914129915129916129917129918129919129920129921129922129923129924129925129926129927129928129929129930129931129932129933129934129935129936129937129938129939129940129941129942129943129944129945129946129947129948129949129950129951129952129953129954129955129956129957129958129959129960129961129962129963129964129965129966129967129968129969129970129971129972129973129974129975129976129977129978129979129980129981129982129983129984129985129986129987129988129989129990129991129992129993129994129995129996129997129998129999130000130001130002130003130004130005130006130007130008130009130010130011130012130013130014130015130016130017130018130019130020130021130022130023130024130025130026130027130028130029130030130031130032130033130034130035130036130037130038130039130040130041130042130043130044130045130046130047130048130049130050130051130052130053130054130055130056130057130058130059130060130061130062130063130064130065130066130067130068130069130070130071130072130073130074130075130076130077130078130079130080130081130082130083130084130085130086130087130088130089130090130091130092130093130094130095130096130097130098130099130100130101130102130103130104130105130106130107130108130109130110130111130112130113130114130115130116130117130118130119130120130121130122130123130124130125130126130127130128130129130130130131130132130133130134130135130136130137130138130139130140130141130142130143130144130145130146130147130148130149130150130151130152130153130154130155130156130157130158130159130160130161130162130163130164130165130166130167130168130169130170130171130172130173130174130175130176130177130178130179130180130181130182130183130184130185130186130187130188130189130190130191130192130193130194130195130196130197130198130199130200130201130202130203130204130205130206130207130208130209130210130211130212130213130214130215130216130217130218130219130220130221130222130223130224130225130226130227130228130229130230130231130232130233130234130235130236130237130238130239130240130241130242130243130244130245130246130247130248130249130250130251130252130253130254130255130256130257130258130259130260130261130262130263130264130265130266130267130268130269130270130271130272130273130274130275130276130277130278130279130280130281130282130283130284130285130286130287130288130289130290130291130292130293130294130295130296130297130298130299130300130301130302130303130304130305130306130307130308130309130310130311130312130313130314130315130316130317130318130319130320130321130322130323130324130325130326130327130328130329130330130331130332130333130334130335130336130337130338130339130340130341130342130343130344130345130346130347130348130349130350130351130352130353130354130355130356130357130358130359130360130361130362130363130364130365130366130367130368130369130370130371130372130373130374130375130376130377130378130379130380130381130382130383130384130385130386130387130388130389130390130391130392130393130394130395130396130397130398130399130400130401130402130403130404130405130406130407130408130409130410130411130412130413130414130415130416130417130418130419130420130421130422130423130424130425130426130427130428130429130430130431130432130433130434130435130436130437130438130439130440130441130442130443130444130445130446130447130448130449130450130451130452130453130454130455130456130457130458130459130460130461130462130463130464130465130466130467130468130469130470130471130472130473130474130475130476130477130478130479130480130481130482130483130484130485130486130487130488130489130490130491130492130493130494130495130496130497130498130499130500130501130502130503130504130505130506130507130508130509130510130511130512130513130514130515130516130517130518130519130520130521130522130523130524130525130526130527130528130529130530130531130532130533130534130535130536130537130538130539130540130541130542130543130544130545130546130547130548130549130550130551130552130553130554130555130556130557130558130559130560130561130562130563130564130565130566130567130568130569130570130571130572130573130574130575130576130577130578130579130580130581130582130583130584130585130586130587130588130589130590130591130592130593130594130595130596130597130598130599130600130601130602130603130604130605130606130607130608130609130610130611130612130613130614130615130616130617130618130619130620130621130622130623130624130625130626130627130628130629130630130631130632130633130634130635130636130637130638130639130640130641130642130643130644130645130646130647130648130649130650130651130652130653130654130655130656130657130658130659130660130661130662130663130664130665130666130667130668130669130670130671130672130673130674130675130676130677130678130679130680130681130682130683130684130685130686130687130688130689130690130691130692130693130694130695130696130697130698130699130700130701130702130703130704130705130706130707130708130709130710130711130712130713130714130715130716130717130718130719130720130721130722130723130724130725130726130727130728130729130730130731130732130733130734130735130736130737130738130739130740130741130742130743130744130745130746130747130748130749130750130751130752130753130754130755130756130757130758130759130760130761130762130763130764130765130766130767130768130769130770130771130772130773130774130775130776130777130778130779130780130781130782130783130784130785130786130787130788130789130790130791130792130793130794130795130796130797130798130799130800130801130802130803130804130805130806130807130808130809130810130811130812130813130814130815130816130817130818130819130820130821130822130823130824130825130826130827130828130829130830130831130832130833130834130835130836130837130838130839130840130841130842130843130844130845130846130847130848130849130850130851130852130853130854130855130856130857130858130859130860130861130862130863130864130865130866130867130868130869130870130871130872130873130874130875130876130877130878130879130880130881130882130883130884130885130886130887130888130889130890130891130892130893130894130895130896130897130898130899130900130901130902130903130904130905130906130907130908130909130910130911130912130913130914130915130916130917130918130919130920130921130922130923130924130925130926130927130928130929130930130931130932130933130934130935130936130937130938130939130940130941130942130943130944130945130946130947130948130949130950130951130952130953130954130955130956130957130958130959130960130961130962130963130964130965130966130967130968130969130970130971130972130973130974130975130976130977130978130979130980130981130982130983130984130985130986130987130988130989130990130991130992130993130994130995130996130997130998130999131000131001131002131003131004131005131006131007131008131009131010131011131012131013131014131015131016131017131018131019131020131021131022131023131024131025131026131027131028131029131030131031131032131033131034131035131036131037131038131039131040131041131042131043131044131045131046131047131048131049131050131051131052131053131054131055131056131057131058131059131060131061131062131063131064131065131066131067131068131069131070131071131072131073131074131075131076131077131078131079131080131081131082131083131084131085131086131087131088131089131090131091131092131093131094131095131096131097131098131099131100131101131102131103131104131105131106131107131108131109131110131111131112131113131114131115131116131117131118131119131120131121131122131123131124131125131126131127131128131129131130131131131132131133131134131135131136131137131138131139131140131141131142131143131144131145131146131147131148131149131150131151131152131153131154131155131156131157131158131159131160131161131162131163131164131165131166131167131168131169131170131171131172131173131174131175131176131177131178131179131180131181131182131183131184131185131186131187131188131189131190131191131192131193131194131195131196131197131198131199131200131201131202131203131204131205131206131207131208131209131210131211131212131213131214131215131216131217131218131219131220131221131222131223131224131225131226131227131228131229131230131231131232131233131234131235131236131237131238131239131240131241131242131243131244131245131246131247131248131249131250131251131252131253131254131255131256131257131258131259131260131261131262131263131264131265131266131267131268131269131270131271131272131273131274131275131276131277131278131279131280131281131282131283131284131285131286131287131288131289131290131291131292131293131294131295131296131297131298131299131300131301131302131303131304131305131306131307131308131309131310131311131312131313131314131315131316131317131318131319131320131321131322131323131324131325131326131327131328131329131330131331131332131333131334131335131336131337131338131339131340131341131342131343131344131345131346131347131348131349131350131351131352131353131354131355131356131357131358131359131360131361131362131363131364131365131366131367131368131369131370131371131372131373131374131375131376131377131378131379131380131381131382131383131384131385131386131387131388131389131390131391131392131393131394131395131396131397131398131399131400131401131402131403131404131405131406131407131408131409131410131411131412131413131414131415131416131417131418131419131420131421131422131423131424131425131426131427131428131429131430131431131432131433131434131435131436131437131438131439131440131441131442131443131444131445131446131447131448131449131450131451131452131453131454131455131456131457131458131459131460131461131462131463131464131465131466131467131468131469131470131471131472131473131474131475131476131477131478131479131480131481131482131483131484131485131486131487131488131489131490131491131492131493131494131495131496131497131498131499131500131501131502131503131504131505131506131507131508131509131510131511131512131513131514131515131516131517131518131519131520131521131522131523131524131525131526131527131528131529131530131531131532131533131534131535131536131537131538131539131540131541131542131543131544131545131546131547131548131549131550131551131552131553131554131555131556131557131558131559131560131561131562131563131564131565131566131567131568131569131570131571131572131573131574131575131576131577131578131579131580131581131582131583131584131585131586131587131588131589131590131591131592131593131594131595131596131597131598131599131600131601131602131603131604131605131606131607131608131609131610131611131612131613131614131615131616131617131618131619131620131621131622131623131624131625131626131627131628131629131630131631131632131633131634131635131636131637131638131639131640131641131642131643131644131645131646131647131648131649131650131651131652131653131654131655131656131657131658131659131660131661131662131663131664131665131666131667131668131669131670131671131672131673131674131675131676131677131678131679131680131681131682131683131684131685131686131687131688131689131690131691131692131693131694131695131696131697131698131699131700131701131702131703131704131705131706131707131708131709131710131711131712131713131714131715131716131717131718131719131720131721131722131723131724131725131726131727131728131729131730131731131732131733131734131735131736131737131738131739131740131741131742131743131744131745131746131747131748131749131750131751131752131753131754131755131756131757131758131759131760131761131762131763131764131765131766131767131768131769131770131771131772131773131774131775131776131777131778131779131780131781131782131783131784131785131786131787131788131789131790131791131792131793131794131795131796131797131798131799131800131801131802131803131804131805131806131807131808131809131810131811131812131813131814131815131816131817131818131819131820131821131822131823131824131825131826131827131828131829131830131831131832131833131834131835131836131837131838131839131840131841131842131843131844131845131846131847131848131849131850131851131852131853131854131855131856131857131858131859131860131861131862131863131864131865131866131867131868131869131870131871131872131873131874131875131876131877131878131879131880131881131882131883131884131885131886131887131888131889131890131891131892131893131894131895131896131897131898131899131900131901131902131903131904131905131906131907131908131909131910131911131912131913131914131915131916131917131918131919131920131921131922131923131924131925131926131927131928131929131930131931131932131933131934131935131936131937131938131939131940131941131942131943131944131945131946131947131948131949131950131951131952131953131954131955131956131957131958131959131960131961131962131963131964131965131966131967131968131969131970131971131972131973131974131975131976131977131978131979131980131981131982131983131984131985131986131987131988131989131990131991131992131993131994131995131996131997131998131999132000132001132002132003132004132005132006132007132008132009132010132011132012132013132014132015132016132017132018132019132020132021132022132023132024132025132026132027132028132029132030132031132032132033132034132035132036132037132038132039132040132041132042132043132044132045132046132047132048132049132050132051132052132053132054132055132056132057132058132059132060132061132062132063132064132065132066132067132068132069132070132071132072132073132074132075132076132077132078132079132080132081132082132083132084132085132086132087132088132089132090132091132092132093132094132095132096132097132098132099132100132101132102132103132104132105132106132107132108132109132110132111132112132113132114132115132116132117132118132119132120132121132122132123132124132125132126132127132128132129132130132131132132132133132134132135132136132137132138132139132140132141132142132143132144132145132146132147132148132149132150132151132152132153132154132155132156132157132158132159132160132161132162132163132164132165132166132167132168132169132170132171132172132173132174132175132176132177132178132179132180132181132182132183132184132185132186132187132188132189132190132191132192132193132194132195132196132197132198132199132200132201132202132203132204132205132206132207132208132209132210132211132212132213132214132215132216132217132218132219132220132221132222132223132224132225132226132227132228132229132230132231132232132233132234132235132236132237132238132239132240132241132242132243132244132245132246132247132248132249132250132251132252132253132254132255132256132257132258132259132260132261132262132263132264132265132266132267132268132269132270132271132272132273132274132275132276132277132278132279132280132281132282132283132284132285132286132287132288132289132290132291132292132293132294132295132296132297132298132299132300132301132302132303132304132305132306132307132308132309132310132311132312132313132314132315132316132317132318132319132320132321132322132323132324132325132326132327132328132329132330132331132332132333132334132335132336132337132338132339132340132341132342132343132344132345132346132347132348132349132350132351132352132353132354132355132356132357132358132359132360132361132362132363132364132365132366132367132368132369132370132371132372132373132374132375132376132377132378132379132380132381132382132383132384132385132386132387132388132389132390132391132392132393132394132395132396132397132398132399132400132401132402132403132404132405132406132407132408132409132410132411132412132413132414132415132416132417132418132419132420132421132422132423132424132425132426132427132428132429132430132431132432132433132434132435132436132437132438132439132440132441132442132443132444132445132446132447132448132449132450132451132452132453132454132455132456132457132458132459132460132461132462132463132464132465132466132467132468132469132470132471132472132473132474132475132476132477132478132479132480132481132482132483132484132485132486132487132488132489132490132491132492132493132494132495132496132497132498132499132500132501132502132503132504132505132506132507132508132509132510132511132512132513132514132515132516132517132518132519132520132521132522132523132524132525132526132527132528132529132530132531132532132533132534132535132536132537132538132539132540132541132542132543132544132545132546132547132548132549132550132551132552132553132554132555132556132557132558132559132560132561132562132563132564132565132566132567132568132569132570132571132572132573132574132575132576132577132578132579132580132581132582132583132584132585132586132587132588132589132590132591132592132593132594132595132596132597132598132599132600132601132602132603132604132605132606132607132608132609132610132611132612132613132614132615132616132617132618132619132620132621132622132623132624132625132626132627132628132629132630132631132632132633132634132635132636132637132638132639132640132641132642132643132644132645132646132647132648132649132650132651132652132653132654132655132656132657132658132659132660132661132662132663132664132665132666132667132668132669132670132671132672132673132674132675132676132677132678132679132680132681132682132683132684132685132686132687132688132689132690132691132692132693132694132695132696132697132698132699132700132701132702132703132704132705132706132707132708132709132710132711132712132713132714132715132716132717132718132719132720132721132722132723132724132725132726132727132728132729132730132731132732132733132734132735132736132737132738132739132740132741132742132743132744132745132746132747132748132749132750132751132752132753132754132755132756132757132758132759132760132761132762132763132764132765132766132767132768132769132770132771132772132773132774132775132776132777132778132779132780132781132782132783132784132785132786132787132788132789132790132791132792132793132794132795132796132797132798132799132800132801132802132803132804132805132806132807132808132809132810132811132812132813132814132815132816132817132818132819132820132821132822132823132824132825132826132827132828132829132830132831132832132833132834132835132836132837132838132839132840132841132842132843132844132845132846132847132848132849132850132851132852132853132854132855132856132857132858132859132860132861132862132863132864132865132866132867132868132869132870132871132872132873132874132875132876132877132878132879132880132881132882132883132884132885132886132887132888132889132890132891132892132893132894132895132896132897132898132899132900132901132902132903132904132905132906132907132908132909132910132911132912132913132914132915132916132917132918132919132920132921132922132923132924132925132926132927132928132929132930132931132932132933132934132935132936132937132938132939132940132941132942132943132944132945132946132947132948132949132950132951132952132953132954132955132956132957132958132959132960132961132962132963132964132965132966132967132968132969132970132971132972132973132974132975132976132977132978132979132980132981132982132983132984132985132986132987132988132989132990132991132992132993132994132995132996132997132998132999133000133001133002133003133004133005133006133007133008133009133010133011133012133013133014133015133016133017133018133019133020133021133022133023133024133025133026133027133028133029133030133031133032133033133034133035133036133037133038133039133040133041133042133043133044133045133046133047133048133049133050133051133052133053133054133055133056133057133058133059133060133061133062133063133064133065133066133067133068133069133070133071133072133073133074133075133076133077133078133079133080133081133082133083133084133085133086133087133088133089133090133091133092133093133094133095133096133097133098133099133100133101133102133103133104133105133106133107133108133109133110133111133112133113133114133115133116133117133118133119133120133121133122133123133124133125133126133127133128133129133130133131133132133133133134133135133136133137133138133139133140133141133142133143133144133145133146133147133148133149133150133151133152133153133154133155133156133157133158133159133160133161133162133163133164133165133166133167133168133169133170133171133172133173133174133175133176133177133178133179133180133181133182133183133184133185133186133187133188133189133190133191133192133193133194133195133196133197133198133199133200133201133202133203133204133205133206133207133208133209133210133211133212133213133214133215133216133217133218133219133220133221133222133223133224133225133226133227133228133229133230133231133232133233133234133235133236133237133238133239133240133241133242133243133244133245133246133247133248133249133250133251133252133253133254133255133256133257133258133259133260133261133262133263133264133265133266133267133268133269133270133271133272133273133274133275133276133277133278133279133280133281133282133283133284133285133286133287133288133289133290133291133292133293133294133295133296133297133298133299133300133301133302133303133304133305133306133307133308133309133310133311133312133313133314133315133316133317133318133319133320133321133322133323133324133325133326133327133328133329133330133331133332133333133334133335133336133337133338133339133340133341133342133343133344133345133346133347133348133349133350133351133352133353133354133355133356133357133358133359133360133361133362133363133364133365133366133367133368133369133370133371133372133373133374133375133376133377133378133379133380133381133382133383133384133385133386133387133388133389133390133391133392133393133394133395133396133397133398133399133400133401133402133403133404133405133406133407133408133409133410133411133412133413133414133415133416133417133418133419133420133421133422133423133424133425133426133427133428133429133430133431133432133433133434133435133436133437133438133439133440133441133442133443133444133445133446133447133448133449133450133451133452133453133454133455133456133457133458133459133460133461133462133463133464133465133466133467133468133469133470133471133472133473133474133475133476133477133478133479133480133481133482133483133484133485133486133487133488133489133490133491133492133493133494133495133496133497133498133499133500133501133502133503133504133505133506133507133508133509133510133511133512133513133514133515133516133517133518133519133520133521133522133523133524133525133526133527133528133529133530133531133532133533133534133535133536133537133538133539133540133541133542133543133544133545133546133547133548133549133550133551133552133553133554133555133556133557133558133559133560133561133562133563133564133565133566133567133568133569133570133571133572133573133574133575133576133577133578133579133580133581133582133583133584133585133586133587133588133589133590133591133592133593133594133595133596133597133598133599133600133601133602133603133604133605133606133607133608133609133610133611133612133613133614133615133616133617133618133619133620133621133622133623133624133625133626133627133628133629133630133631133632133633133634133635133636133637133638133639133640133641133642133643133644133645133646133647133648133649133650133651133652133653133654133655133656133657133658133659133660133661133662133663133664133665133666133667133668133669133670133671133672133673133674133675133676133677133678133679133680133681133682133683133684133685133686133687133688133689133690133691133692133693133694133695133696133697133698133699133700133701133702133703133704133705133706133707133708133709133710133711133712133713133714133715133716133717133718133719133720133721133722133723133724133725133726133727133728133729133730133731133732133733133734133735133736133737133738133739133740133741133742133743133744133745133746133747133748133749133750133751133752133753133754133755133756133757133758133759133760133761133762133763133764133765133766133767133768133769133770133771133772133773133774133775133776133777133778133779133780133781133782133783133784133785133786133787133788133789133790133791133792133793133794133795133796133797133798133799133800133801133802133803133804133805133806133807133808133809133810133811133812133813133814133815133816133817133818133819133820133821133822133823133824133825133826133827133828133829133830133831133832133833133834133835133836133837133838133839133840133841133842133843133844133845133846133847133848133849133850133851133852133853133854133855133856133857133858133859133860133861133862133863133864133865133866133867133868133869133870133871133872133873133874133875133876133877133878133879133880133881133882133883133884133885133886133887133888133889133890133891133892133893133894133895133896133897133898133899133900133901133902133903133904133905133906133907133908133909133910133911133912133913133914133915133916133917133918133919133920133921133922133923133924133925133926133927133928133929133930133931133932133933133934133935133936133937133938133939133940133941133942133943133944133945133946133947133948133949133950133951133952133953133954133955133956133957133958133959133960133961133962133963133964133965133966133967133968133969133970133971133972133973133974133975133976133977133978133979133980133981133982133983133984133985133986133987133988133989133990133991133992133993133994133995133996133997133998133999134000134001134002134003134004134005134006134007134008134009134010134011134012134013134014134015134016134017134018134019134020134021134022134023134024134025134026134027134028134029134030134031134032134033134034134035134036134037134038134039134040134041134042134043134044134045134046134047134048134049134050134051134052134053134054134055134056134057134058134059134060134061134062134063134064134065134066134067134068134069134070134071134072134073134074134075134076134077134078134079134080134081134082134083134084134085134086134087134088134089134090134091134092134093134094134095134096134097134098134099134100134101134102134103134104134105134106134107134108134109134110134111134112134113134114134115134116134117134118134119134120134121134122134123134124134125134126134127134128134129134130134131134132134133134134134135134136134137134138134139134140134141134142134143134144134145134146134147134148134149134150134151134152134153134154134155134156134157134158134159134160134161134162134163134164134165134166134167134168134169134170134171134172134173134174134175134176134177134178134179134180134181134182134183134184134185134186134187134188134189134190134191134192134193134194134195134196134197134198134199134200134201134202134203134204134205134206134207134208134209134210134211134212134213134214134215134216134217134218134219134220134221134222134223134224134225134226134227134228134229134230134231134232134233134234134235134236134237134238134239134240134241134242134243134244134245134246134247134248134249134250134251134252134253134254134255134256134257134258134259134260134261134262134263134264134265134266134267134268134269134270134271134272134273134274134275134276134277134278134279134280134281134282134283134284134285134286134287134288134289134290134291134292134293134294134295134296134297134298134299134300134301134302134303134304134305134306134307134308134309134310134311134312134313134314134315134316134317134318134319134320134321134322134323134324134325134326134327134328134329134330134331134332134333134334134335134336134337134338134339134340134341134342134343134344134345134346134347134348134349134350134351134352134353134354134355134356134357134358134359134360134361134362134363134364134365134366134367134368134369134370134371134372134373134374134375134376134377134378134379134380134381134382134383134384134385134386134387134388134389134390134391134392134393134394134395134396134397134398134399134400134401134402134403134404134405134406134407134408134409134410134411134412134413134414134415134416134417134418134419134420134421134422134423134424134425134426134427134428134429134430134431134432134433134434134435134436134437134438134439134440134441134442134443134444134445134446134447134448134449134450134451134452134453134454134455134456134457134458134459134460134461134462134463134464134465134466134467134468134469134470134471134472134473134474134475134476134477134478134479134480134481134482134483134484134485134486134487134488134489134490134491134492134493134494134495134496134497134498134499134500134501134502134503134504134505134506134507134508134509134510134511134512134513134514134515134516134517134518134519134520134521134522134523134524134525134526134527134528134529134530134531134532134533134534134535134536134537134538134539134540134541134542134543134544134545134546134547134548134549134550134551134552134553134554134555134556134557134558134559134560134561134562134563134564134565134566134567134568134569134570134571134572134573134574134575134576134577134578134579134580134581134582134583134584134585134586134587134588134589134590134591134592134593134594134595134596134597134598134599134600134601134602134603134604134605134606134607134608134609134610134611134612134613134614134615134616134617134618134619134620134621134622134623134624134625134626134627134628134629134630134631134632134633134634134635134636134637134638134639134640134641134642134643134644134645134646134647134648134649134650134651134652134653134654134655134656134657134658134659134660134661134662134663134664134665134666134667134668134669134670134671134672134673134674134675134676134677134678134679134680134681134682134683134684134685134686134687134688134689134690134691134692134693134694134695134696134697134698134699134700134701134702134703134704134705134706134707134708134709134710134711134712134713134714134715134716134717134718134719134720134721134722134723134724134725134726134727134728134729134730134731134732134733134734134735134736134737134738134739134740134741134742134743134744134745134746134747134748134749134750134751134752134753134754134755134756134757134758134759134760134761134762134763134764134765134766134767134768134769134770134771134772134773134774134775134776134777134778134779134780134781134782134783134784134785134786134787134788134789134790134791134792134793134794134795134796134797134798134799134800134801134802134803134804134805134806134807134808134809134810134811134812134813134814134815134816134817134818134819134820134821134822134823134824134825134826134827134828134829134830134831134832134833134834134835134836134837134838134839134840134841134842134843134844134845134846134847134848134849134850134851134852134853134854134855134856134857134858134859134860134861134862134863134864134865134866134867134868134869134870134871134872134873134874134875134876134877134878134879134880134881134882134883134884134885134886134887134888134889134890134891134892134893134894134895134896134897134898134899134900134901134902134903134904134905134906134907134908134909134910134911134912134913134914134915134916134917134918134919134920134921134922134923134924134925134926134927134928134929134930134931134932134933134934134935134936134937134938134939134940134941134942134943134944134945134946134947134948134949134950134951134952134953134954134955134956134957134958134959134960134961134962134963134964134965134966134967134968134969134970134971134972134973134974134975134976134977134978134979134980134981134982134983134984134985134986134987134988134989134990134991134992134993134994134995134996134997134998134999135000135001135002135003135004135005135006135007135008135009135010135011135012135013135014135015135016135017135018135019135020135021135022135023135024135025135026135027135028135029135030135031135032135033135034135035135036135037135038135039135040135041135042135043135044135045135046135047135048135049135050135051135052135053135054135055135056135057135058135059135060135061135062135063135064135065135066135067135068135069135070135071135072135073135074135075135076135077135078135079135080135081135082135083135084135085135086135087135088135089135090135091135092135093135094135095135096135097135098135099135100135101135102135103135104135105135106135107135108135109135110135111135112135113135114135115135116135117135118135119135120135121135122135123135124135125135126135127135128135129135130135131135132135133135134135135135136135137135138135139135140135141135142135143135144135145135146135147135148135149135150135151135152135153135154135155135156135157135158135159135160135161135162135163135164135165135166135167135168135169135170135171135172135173135174135175135176135177135178135179135180135181135182135183135184135185135186135187135188135189135190135191135192135193135194135195135196135197135198135199135200135201135202135203135204135205135206135207135208135209135210135211135212135213135214135215135216135217135218135219135220135221135222135223135224135225135226135227135228135229135230135231135232135233135234135235135236135237135238135239135240135241135242135243135244135245135246135247135248135249135250135251135252135253135254135255135256135257135258135259135260135261135262135263135264135265135266135267135268135269135270135271135272135273135274135275135276135277135278135279135280135281135282135283135284135285135286135287135288135289135290135291135292135293135294135295135296135297135298135299135300135301135302135303135304135305135306135307135308135309135310135311135312135313135314135315135316135317135318135319135320135321135322135323135324135325135326135327135328135329135330135331135332135333135334135335135336135337135338135339135340135341135342135343135344135345135346135347135348135349135350135351135352135353135354135355135356135357135358135359135360135361135362135363135364135365135366135367135368135369135370135371135372135373135374135375135376135377135378135379135380135381135382135383135384135385135386135387135388135389135390135391135392135393135394135395135396135397135398135399135400135401135402135403135404135405135406135407135408135409135410135411135412135413135414135415135416135417135418135419135420135421135422135423135424135425135426135427135428135429135430135431135432135433135434135435135436135437135438135439135440135441135442135443135444135445135446135447135448135449135450135451135452135453135454135455135456135457135458135459135460135461135462135463135464135465135466135467135468135469135470135471135472135473135474135475135476135477135478135479135480135481135482135483135484135485135486135487135488135489135490135491135492135493135494135495135496135497135498135499135500135501135502135503135504135505135506135507135508135509135510135511135512135513135514135515135516135517135518135519135520135521135522135523135524135525135526135527135528135529135530135531135532135533135534135535135536135537135538135539135540135541135542135543135544135545135546135547135548135549135550135551135552135553135554135555135556135557135558135559135560135561135562135563135564135565135566135567135568135569135570135571135572135573135574135575135576135577135578135579135580135581135582135583135584135585135586135587135588135589135590135591135592135593135594135595135596135597135598135599135600135601135602135603135604135605135606135607135608135609135610135611135612135613135614135615135616135617135618135619135620135621135622135623135624135625135626135627135628135629135630135631135632135633135634135635135636135637135638135639135640135641135642135643135644135645135646135647135648135649135650135651135652135653135654135655135656135657135658135659135660135661135662135663135664135665135666135667135668135669135670135671135672135673135674135675135676135677135678135679135680135681135682135683135684135685135686135687135688135689135690135691135692135693135694135695135696135697135698135699135700135701135702135703135704135705135706135707135708135709135710135711135712135713135714135715135716135717135718135719135720135721135722135723135724135725135726135727135728135729135730135731135732135733135734135735135736135737135738135739135740135741135742135743135744135745135746135747135748135749135750135751135752135753135754135755135756135757135758135759135760135761135762135763135764135765135766135767135768135769135770135771135772135773135774135775135776135777135778135779135780135781135782135783135784135785135786135787135788135789135790135791135792135793135794135795135796135797135798135799135800135801135802135803135804135805135806135807135808135809135810135811135812135813135814135815135816135817135818135819135820135821135822135823135824135825135826135827135828135829135830135831135832135833135834135835135836135837135838135839135840135841135842135843135844135845135846135847135848135849135850135851135852135853135854135855135856135857135858135859135860135861135862135863135864135865135866135867135868135869135870135871135872135873135874135875135876135877135878135879135880135881135882135883135884135885135886135887135888135889135890135891135892135893135894135895135896135897135898135899135900135901135902135903135904135905135906135907135908135909135910135911135912135913135914135915135916135917135918135919135920135921135922135923135924135925135926135927135928135929135930135931135932135933135934135935135936135937135938135939135940135941135942135943135944135945135946135947135948135949135950135951135952135953135954135955135956135957135958135959135960135961135962135963135964135965135966135967135968135969135970135971135972135973135974135975135976135977135978135979135980135981135982135983135984135985135986135987135988135989135990135991135992135993135994135995135996135997135998135999136000136001136002136003136004136005136006136007136008136009136010136011136012136013136014136015136016136017136018136019136020136021136022136023136024136025136026136027136028136029136030136031136032136033136034136035136036136037136038136039136040136041136042136043136044136045136046136047136048136049136050136051136052136053136054136055136056136057136058136059136060136061136062136063136064136065136066136067136068136069136070136071136072136073136074136075136076136077136078136079136080136081136082136083136084136085136086136087136088136089136090136091136092136093136094136095136096136097136098136099136100136101136102136103136104136105136106136107136108136109136110136111136112136113136114136115136116136117136118136119136120136121136122136123136124136125136126136127136128136129136130136131136132136133136134136135136136136137136138136139136140136141136142136143136144136145136146136147136148136149136150136151136152136153136154136155136156136157136158136159136160136161136162136163136164136165136166136167136168136169136170136171136172136173136174136175136176136177136178136179136180136181136182136183136184136185136186136187136188136189136190136191136192136193136194136195136196136197136198136199136200136201136202136203136204136205136206136207136208136209136210136211136212136213136214136215136216136217136218136219136220136221136222136223136224136225136226136227136228136229136230136231136232136233136234136235136236136237136238136239136240136241136242136243136244136245136246136247136248136249136250136251136252136253136254136255136256136257136258136259136260136261136262136263136264136265136266136267136268136269136270136271136272136273136274136275136276136277136278136279136280136281136282136283136284136285136286136287136288136289136290136291136292136293136294136295136296136297136298136299136300136301136302136303136304136305136306136307136308136309136310136311136312136313136314136315136316136317136318136319136320136321136322136323136324136325136326136327136328136329136330136331136332136333136334136335136336136337136338136339136340136341136342136343136344136345136346136347136348136349136350136351136352136353136354136355136356136357136358136359136360136361136362136363136364136365136366136367136368136369136370136371136372136373136374136375136376136377136378136379136380136381136382136383136384136385136386136387136388136389136390136391136392136393136394136395136396136397136398136399136400136401136402136403136404136405136406136407136408136409136410136411136412136413136414136415136416136417136418136419136420136421136422136423136424136425136426136427136428136429136430136431136432136433136434136435136436136437136438136439136440136441136442136443136444136445136446136447136448136449136450136451136452136453136454136455136456136457136458136459136460136461136462136463136464136465136466136467136468136469136470136471136472136473136474136475136476136477136478136479136480136481136482136483136484136485136486136487136488136489136490136491136492136493136494136495136496136497136498136499136500136501136502136503136504136505136506136507136508136509136510136511136512136513136514136515136516136517136518136519136520136521136522136523136524136525136526136527136528136529136530136531136532136533136534136535136536136537136538136539136540136541136542136543136544136545136546136547136548136549136550136551136552136553136554136555136556136557136558136559136560136561136562136563136564136565136566136567136568136569136570136571136572136573136574136575136576136577136578136579136580136581136582136583136584136585136586136587136588136589136590136591136592136593136594136595136596136597136598136599136600136601136602136603136604136605136606136607136608136609136610136611136612136613136614136615136616136617136618136619136620136621136622136623136624136625136626136627136628136629136630136631136632136633136634136635136636136637136638136639136640136641136642136643136644136645136646136647136648136649136650136651136652136653136654136655136656136657136658136659136660136661136662136663136664136665136666136667136668136669136670136671136672136673136674136675136676136677136678136679136680136681136682136683136684136685136686136687136688136689136690136691136692136693136694136695136696136697136698136699136700136701136702136703136704136705136706136707136708136709136710136711136712136713136714136715136716136717136718136719136720136721136722136723136724136725136726136727136728136729136730136731136732136733136734136735136736136737136738136739136740136741136742136743136744136745136746136747136748136749136750136751136752136753136754136755136756136757136758136759136760136761136762136763136764136765136766136767136768136769136770136771136772136773136774136775136776136777136778136779136780136781136782136783136784136785136786136787136788136789136790136791136792136793136794136795136796136797136798136799136800136801136802136803136804136805136806136807136808136809136810136811136812136813136814136815136816136817136818136819136820136821136822136823136824136825136826136827136828136829136830136831136832136833136834136835136836136837136838136839136840136841136842136843136844136845136846136847136848136849136850136851136852136853136854136855136856136857136858136859136860136861136862136863136864136865136866136867136868136869136870136871136872136873136874136875136876136877136878136879136880136881136882136883136884136885136886136887136888136889136890136891136892136893136894136895136896136897136898136899136900136901136902136903136904136905136906136907136908136909136910136911136912136913136914136915136916136917136918136919136920136921136922136923136924136925136926136927136928136929136930136931136932136933136934136935136936136937136938136939136940136941136942136943136944136945136946136947136948136949136950136951136952136953136954136955136956136957136958136959136960136961136962136963136964136965136966136967136968136969136970136971136972136973136974136975136976136977136978136979136980136981136982136983136984136985136986136987136988136989136990136991136992136993136994136995136996136997136998136999137000137001137002137003137004137005137006137007137008137009137010137011137012137013137014137015137016137017137018137019137020137021137022137023137024137025137026137027137028137029137030137031137032137033137034137035137036137037137038137039137040137041137042137043137044137045137046137047137048137049137050137051137052137053137054137055137056137057137058137059137060137061137062137063137064137065137066137067137068137069137070137071137072137073137074137075137076137077137078137079137080137081137082137083137084137085137086137087137088137089137090137091137092137093137094137095137096137097137098137099137100137101137102137103137104137105137106137107137108137109137110137111137112137113137114137115137116137117137118137119137120137121137122137123137124137125137126137127137128137129137130137131137132137133137134137135137136137137137138137139137140137141137142137143137144137145137146137147137148137149137150137151137152137153137154137155137156137157137158137159137160137161137162137163137164137165137166137167137168137169137170137171137172137173137174137175137176137177137178137179137180137181137182137183137184137185137186137187137188137189137190137191137192137193137194137195137196137197137198137199137200137201137202137203137204137205137206137207137208137209137210137211137212137213137214137215137216137217137218137219137220137221137222137223137224137225137226137227137228137229137230137231137232137233137234137235137236137237137238137239137240137241137242137243137244137245137246137247137248137249137250137251137252137253137254137255137256137257137258137259137260137261137262137263137264137265137266137267137268137269137270137271137272137273137274137275137276137277137278137279137280137281137282137283137284137285137286137287137288137289137290137291137292137293137294137295137296137297137298137299137300137301137302137303137304137305137306137307137308137309137310137311137312137313137314137315137316137317137318137319137320137321137322137323137324137325137326137327137328137329137330137331137332137333137334137335137336137337137338137339137340137341137342137343137344137345137346137347137348137349137350137351137352137353137354137355137356137357137358137359137360137361137362137363137364137365137366137367137368137369137370137371137372137373137374137375137376137377137378137379137380137381137382137383137384137385137386137387137388137389137390137391137392137393137394137395137396137397137398137399137400137401137402137403137404137405137406137407137408137409137410137411137412137413137414137415137416137417137418137419137420137421137422137423137424137425137426137427137428137429137430137431137432137433137434137435137436137437137438137439137440137441137442137443137444137445137446137447137448137449137450137451137452137453137454137455137456137457137458137459137460137461137462137463137464137465137466137467137468137469137470137471137472137473137474137475137476137477137478137479137480137481137482137483137484137485137486137487137488137489137490137491137492137493137494137495137496137497137498137499137500137501137502137503137504137505137506137507137508137509137510137511137512137513137514137515137516137517137518137519137520137521137522137523137524137525137526137527137528137529137530137531137532137533137534137535137536137537137538137539137540137541137542137543137544137545137546137547137548137549137550137551137552137553137554137555137556137557137558137559137560137561137562137563137564137565137566137567137568137569137570137571137572137573137574137575137576137577137578137579137580137581137582137583137584137585137586137587137588137589137590137591137592137593137594137595137596137597137598137599137600137601137602137603137604137605137606137607137608137609137610137611137612137613137614137615137616137617137618137619137620137621137622137623137624137625137626137627137628137629137630137631137632137633137634137635137636137637137638137639137640137641137642137643137644137645137646137647137648137649137650137651137652137653137654137655137656137657137658137659137660137661137662137663137664137665137666137667137668137669137670137671137672137673137674137675137676137677137678137679137680137681137682137683137684137685137686137687137688137689137690137691137692137693137694137695137696137697137698137699137700137701137702137703137704137705137706137707137708137709137710137711137712137713137714137715137716137717137718137719137720137721137722137723137724137725137726137727137728137729137730137731137732137733137734137735137736137737137738137739137740137741137742137743137744137745137746137747137748137749137750137751137752137753137754137755137756137757137758137759137760137761137762137763137764137765137766137767137768137769137770137771137772137773137774137775137776137777137778137779137780137781137782137783137784137785137786137787137788137789137790137791137792137793137794137795137796137797137798137799137800137801137802137803137804137805137806137807137808137809137810137811137812137813137814137815137816137817137818137819137820137821137822137823137824137825137826137827137828137829137830137831137832137833137834137835137836137837137838137839137840137841137842137843137844137845137846137847137848137849137850137851137852137853137854137855137856137857137858137859137860137861137862137863137864137865137866137867137868137869137870137871137872137873137874137875137876137877137878137879137880137881137882137883137884137885137886137887137888137889137890137891137892137893137894137895137896137897137898137899137900137901137902137903137904137905137906137907137908137909137910137911137912137913137914137915137916137917137918137919137920137921137922137923137924137925137926137927137928137929137930137931137932137933137934137935137936137937137938137939137940137941137942137943137944137945137946137947137948137949137950137951137952137953137954137955137956137957137958137959137960137961137962137963137964137965137966137967137968137969137970137971137972137973137974137975137976137977137978137979137980137981137982137983137984137985137986137987137988137989137990137991137992137993137994137995137996137997137998137999138000138001138002138003138004138005138006138007138008138009138010138011138012138013138014138015138016138017138018138019138020138021138022138023138024138025138026138027138028138029138030138031138032138033138034138035138036138037138038138039138040138041138042138043138044138045138046138047138048138049138050138051138052138053138054138055138056138057138058138059138060138061138062138063138064138065138066138067138068138069138070138071138072138073138074138075138076138077138078138079138080138081138082138083138084138085138086138087138088138089138090138091138092138093138094138095138096138097138098138099138100138101138102138103138104138105138106138107138108138109138110138111138112138113138114138115138116138117138118138119138120138121138122138123138124138125138126138127138128138129138130138131138132138133138134138135138136138137138138138139138140138141138142138143138144138145138146138147138148138149138150138151138152138153138154138155138156138157138158138159138160138161138162138163138164138165138166138167138168138169138170138171138172138173138174138175138176138177138178138179138180138181138182138183138184138185138186138187138188138189138190138191138192138193138194138195138196138197138198138199138200138201138202138203138204138205138206138207138208138209138210138211138212138213138214138215138216138217138218138219138220138221138222138223138224138225138226138227138228138229138230138231138232138233138234138235138236138237138238138239138240138241138242138243138244138245138246138247138248138249138250138251138252138253138254138255138256138257138258138259138260138261138262138263138264138265138266138267138268138269138270138271138272138273138274138275138276138277138278138279138280138281138282138283138284138285138286138287138288138289138290138291138292138293138294138295138296138297138298138299138300138301138302138303138304138305138306138307138308138309138310138311138312138313138314138315138316138317138318138319138320138321138322138323138324138325138326138327138328138329138330138331138332138333138334138335138336138337138338138339138340138341138342138343138344138345138346138347138348138349138350138351138352138353138354138355138356138357138358138359138360138361138362138363138364138365138366138367138368138369138370138371138372138373138374138375138376138377138378138379138380138381138382138383138384138385138386138387138388138389138390138391138392138393138394138395138396138397138398138399138400138401138402138403138404138405138406138407138408138409138410138411138412138413138414138415138416138417138418138419138420138421138422138423138424138425138426138427138428138429138430138431138432138433138434138435138436138437138438138439138440138441138442138443138444138445138446138447138448138449138450138451138452138453138454138455138456138457138458138459138460138461138462138463138464138465138466138467138468138469138470138471138472138473138474138475138476138477138478138479138480138481138482138483138484138485138486138487138488138489138490138491138492138493138494138495138496138497138498138499138500138501138502138503138504138505138506138507138508138509138510138511138512138513138514138515138516138517138518138519138520138521138522138523138524138525138526138527138528138529138530138531138532138533138534138535138536138537138538138539138540138541138542138543138544138545138546138547138548138549138550138551138552138553138554138555138556138557138558138559138560138561138562138563138564138565138566138567138568138569138570138571138572138573138574138575138576138577138578138579138580138581138582138583138584138585138586138587138588138589138590138591138592138593138594138595138596138597138598138599138600138601138602138603138604138605138606138607138608138609138610138611138612138613138614138615138616138617138618138619138620138621138622138623138624138625138626138627138628138629138630138631138632138633138634138635138636138637138638138639138640138641138642138643138644138645138646138647138648138649138650138651138652138653138654138655138656138657138658138659138660138661138662138663138664138665138666138667138668138669138670138671138672138673138674138675138676138677138678138679138680138681138682138683138684138685138686138687138688138689138690138691138692138693138694138695138696138697138698138699138700138701138702138703138704138705138706138707138708138709138710138711138712138713138714138715138716138717138718138719138720138721138722138723138724138725138726138727138728138729138730138731138732138733138734138735138736138737138738138739138740138741138742138743138744138745138746138747138748138749138750138751138752138753138754138755138756138757138758138759138760138761138762138763138764138765138766138767138768138769138770138771138772138773138774138775138776138777138778138779138780138781138782138783138784138785138786138787138788138789138790138791138792138793138794138795138796138797138798138799138800138801138802138803138804138805138806138807138808138809138810138811138812138813138814138815138816138817138818138819138820138821138822138823138824138825138826138827138828138829138830138831138832138833138834138835138836138837138838138839138840138841138842138843138844138845138846138847138848138849138850138851138852138853138854138855138856138857138858138859138860138861138862138863138864138865138866138867138868138869138870138871138872138873138874138875138876138877138878138879138880138881138882138883138884138885138886138887138888138889138890138891138892138893138894138895138896138897138898138899138900138901138902138903138904138905138906138907138908138909138910138911138912138913138914138915138916138917138918138919138920138921138922138923138924138925138926138927138928138929138930138931138932138933138934138935138936138937138938138939138940138941138942138943138944138945138946138947138948138949138950138951138952138953138954138955138956138957138958138959138960138961138962138963138964138965138966138967138968138969138970138971138972138973138974138975138976138977138978138979138980138981138982138983138984138985138986138987138988138989138990138991138992138993138994138995138996138997138998138999139000139001139002139003139004139005139006139007139008139009139010139011139012139013139014139015139016139017139018139019139020139021139022139023139024139025139026139027139028139029139030139031139032139033139034139035139036139037139038139039139040139041139042139043139044139045139046139047139048139049139050139051139052139053139054139055139056139057139058139059139060139061139062139063139064139065139066139067139068139069139070139071139072139073139074139075139076139077139078139079139080139081139082139083139084139085139086139087139088139089139090139091139092139093139094139095139096139097139098139099139100139101139102139103139104139105139106139107139108139109139110139111139112139113139114139115139116139117139118139119139120139121139122139123139124139125139126139127139128139129139130139131139132139133139134139135139136139137139138139139139140139141139142139143139144139145139146139147139148139149139150139151139152139153139154139155139156139157139158139159139160139161139162139163139164139165139166139167139168139169139170139171139172139173139174139175139176139177139178139179139180139181139182139183139184139185139186139187139188139189139190139191139192139193139194139195139196139197139198139199139200139201139202139203139204139205139206139207139208139209139210139211139212139213139214139215139216139217139218139219139220139221139222139223139224139225139226139227139228139229139230139231139232139233139234139235139236139237139238139239139240139241139242139243139244139245139246139247139248139249139250139251139252139253139254139255139256139257139258139259139260139261139262139263139264139265139266139267139268139269139270139271139272139273139274139275139276139277139278139279139280139281139282139283139284139285139286139287139288139289139290139291139292139293139294139295139296139297139298139299139300139301139302139303139304139305139306139307139308139309139310139311139312139313139314139315139316139317139318139319139320139321139322139323139324139325139326139327139328139329139330139331139332139333139334139335139336139337139338139339139340139341139342139343139344139345139346139347139348139349139350139351139352139353139354139355139356139357139358139359139360139361139362139363139364139365139366139367139368139369139370139371139372139373139374139375139376139377139378139379139380139381139382139383139384139385139386139387139388139389139390139391139392139393139394139395139396139397139398139399139400139401139402139403139404139405139406139407139408139409139410139411139412139413139414139415139416139417139418139419139420139421139422139423139424139425139426139427139428139429139430139431139432139433139434139435139436139437139438139439139440139441139442139443139444139445139446139447139448139449139450139451139452139453139454139455139456139457139458139459139460139461139462139463139464139465139466139467139468139469139470139471139472139473139474139475139476139477139478139479139480139481139482139483139484139485139486139487139488139489139490139491139492139493139494139495139496139497139498139499139500139501139502139503139504139505139506139507139508139509139510139511139512139513139514139515139516139517139518139519139520139521139522139523139524139525139526139527139528139529139530139531139532139533139534139535139536139537139538139539139540139541139542139543139544139545139546139547139548139549139550139551139552139553139554139555139556139557139558139559139560139561139562139563139564139565139566139567139568139569139570139571139572139573139574139575139576139577139578139579139580139581139582139583139584139585139586139587139588139589139590139591139592139593139594139595139596139597139598139599139600139601139602139603139604139605139606139607139608139609139610139611139612139613139614139615139616139617139618139619139620139621139622139623139624139625139626139627139628139629139630139631139632139633139634139635139636139637139638139639139640139641139642139643139644139645139646139647139648139649139650139651139652139653139654139655139656139657139658139659139660139661139662139663139664139665139666139667139668139669139670139671139672139673139674139675139676139677139678139679139680139681139682139683139684139685139686139687139688139689139690139691139692139693139694139695139696139697139698139699139700139701139702139703139704139705139706139707139708139709139710139711139712139713139714139715139716139717139718139719139720139721139722139723139724139725139726139727139728139729139730139731139732139733139734139735139736139737139738139739139740139741139742139743139744139745139746139747139748139749139750139751139752139753139754139755139756139757139758139759139760139761139762139763139764139765139766139767139768139769139770139771139772139773139774139775139776139777139778139779139780139781139782139783139784139785139786139787139788139789139790139791139792139793139794139795139796139797139798139799139800139801139802139803139804139805139806139807139808139809139810139811139812139813139814139815139816139817139818139819139820139821139822139823139824139825139826139827139828139829139830139831139832139833139834139835139836139837139838139839139840139841139842139843139844139845139846139847139848139849139850139851139852139853139854139855139856139857139858139859139860139861139862139863139864139865139866139867139868139869139870139871139872139873139874139875139876139877139878139879139880139881139882139883139884139885139886139887139888139889139890139891139892139893139894139895139896139897139898139899139900139901139902139903139904139905139906139907139908139909139910139911139912139913139914139915139916139917139918139919139920139921139922139923139924139925139926139927139928139929139930139931139932139933139934139935139936139937139938139939139940139941139942139943139944139945139946139947139948139949139950139951139952139953139954139955139956139957139958139959139960139961139962139963139964139965139966139967139968139969139970139971139972139973139974139975139976139977139978139979139980139981139982139983139984139985139986139987139988139989139990139991139992139993139994139995139996139997139998139999140000140001140002140003140004140005140006140007140008140009140010140011140012140013140014140015140016140017140018140019140020140021140022140023140024140025140026140027140028140029140030140031140032140033140034140035140036140037140038140039140040140041140042140043140044140045140046140047140048140049140050140051140052140053140054140055140056140057140058140059140060140061140062140063140064140065140066140067140068140069140070140071140072140073140074140075140076140077140078140079140080140081140082140083140084140085140086140087140088140089140090140091140092140093140094140095140096140097140098140099140100140101140102140103140104140105140106140107140108140109140110140111140112140113140114140115140116140117140118140119140120140121140122140123140124140125140126140127140128140129140130140131140132140133140134140135140136140137140138140139140140140141140142140143140144140145140146140147140148140149140150140151140152140153140154140155140156140157140158140159140160140161140162140163140164140165140166140167140168140169140170140171140172140173140174140175140176140177140178140179140180140181140182140183140184140185140186140187140188140189140190140191140192140193140194140195140196140197140198140199140200140201140202140203140204140205140206140207140208140209140210140211140212140213140214140215140216140217140218140219140220140221140222140223140224140225140226140227140228140229140230140231140232140233140234140235140236140237140238140239140240140241140242140243140244140245140246140247140248140249140250140251140252140253140254140255140256140257140258140259140260140261140262140263140264140265140266140267140268140269140270140271140272140273140274140275140276140277140278140279140280140281140282140283140284140285140286140287140288140289140290140291140292140293140294140295140296140297140298140299140300140301140302140303140304140305140306140307140308140309140310140311140312140313140314140315140316140317140318140319140320140321140322140323140324140325140326140327140328140329140330140331140332140333140334140335140336140337140338140339140340140341140342140343140344140345140346140347140348140349140350140351140352140353140354140355140356140357140358140359140360140361140362140363140364140365140366140367140368140369140370140371140372140373140374140375140376140377140378140379140380140381140382140383140384140385140386140387140388140389140390140391140392140393140394140395140396140397140398140399140400140401140402140403140404140405140406140407140408140409140410140411140412140413140414140415140416140417140418140419140420140421140422140423140424140425140426140427140428140429140430140431140432140433140434140435140436140437140438140439140440140441140442140443140444140445140446140447140448140449140450140451140452140453140454140455140456140457140458140459140460140461140462140463140464140465140466140467140468140469140470140471140472140473140474140475140476140477140478140479140480140481140482140483140484140485140486140487140488140489140490140491140492140493140494140495140496140497140498140499140500140501140502140503140504140505140506140507140508140509140510140511140512140513140514140515140516140517140518140519140520140521140522140523140524140525140526140527140528140529140530140531140532140533140534140535140536140537140538140539140540140541140542140543140544140545140546140547140548140549140550140551140552140553140554140555140556140557140558140559140560140561140562140563140564140565140566140567140568140569140570140571140572140573140574140575140576140577140578140579140580140581140582140583140584140585140586140587140588140589140590140591140592140593140594140595140596140597140598140599140600140601140602140603140604140605140606140607140608140609140610140611140612140613140614140615140616140617140618140619140620140621140622140623140624140625140626140627140628140629140630140631140632140633140634140635140636140637140638140639140640140641140642140643140644140645140646140647140648140649140650140651140652140653140654140655140656140657140658140659140660140661140662140663140664140665140666140667140668140669140670140671140672140673140674140675140676140677140678140679140680140681140682140683140684140685140686140687140688140689140690140691140692140693140694140695140696140697140698140699140700140701140702140703140704140705140706140707140708140709140710140711140712140713140714140715140716140717140718140719140720140721140722140723140724140725140726140727140728140729140730140731140732140733140734140735140736140737140738140739140740140741140742140743140744140745140746140747140748140749140750140751140752140753140754140755140756140757140758140759140760140761140762140763140764140765140766140767140768140769140770140771140772140773140774140775140776140777140778140779140780140781140782140783140784140785140786140787140788140789140790140791140792140793140794140795140796140797140798140799140800140801140802140803140804140805140806140807140808140809140810140811140812140813140814140815140816140817140818140819140820140821140822140823140824140825140826140827140828140829140830140831140832140833140834140835140836140837140838140839140840140841140842140843140844140845140846140847140848140849140850140851140852140853140854140855140856140857140858140859140860140861140862140863140864140865140866140867140868140869140870140871140872140873140874140875140876140877140878140879140880140881140882140883140884140885140886140887140888140889140890140891140892140893140894140895140896140897140898140899140900140901140902140903140904140905140906140907140908140909140910140911140912140913140914140915140916140917140918140919140920140921140922140923140924140925140926140927140928140929140930140931140932140933140934140935140936140937140938140939140940140941140942140943140944140945140946140947140948140949140950140951140952140953140954140955140956140957140958140959140960140961140962140963140964140965140966140967140968140969140970140971140972140973140974140975140976140977140978140979140980140981140982140983140984140985140986140987140988140989140990140991140992140993140994140995140996140997140998140999141000141001141002141003141004141005141006141007141008141009141010141011141012141013141014141015141016141017141018141019141020141021141022141023141024141025141026141027141028141029141030141031141032141033141034141035141036141037141038141039141040141041141042141043141044141045141046141047141048141049141050141051141052141053141054141055141056141057141058141059141060141061141062141063141064141065141066141067141068141069141070141071141072141073141074141075141076141077141078141079141080141081141082141083141084141085141086141087141088141089141090141091141092141093141094141095141096141097141098141099141100141101141102141103141104141105141106141107141108141109141110141111141112141113141114141115141116141117141118141119141120141121141122141123141124141125141126141127141128141129141130141131141132141133141134141135141136141137141138141139141140141141141142141143141144141145141146141147141148141149141150141151141152141153141154141155141156141157141158141159141160141161141162141163141164141165141166141167141168141169141170141171141172141173141174141175141176141177141178141179141180141181141182141183141184141185141186141187141188141189141190141191141192141193141194141195141196141197141198141199141200141201141202141203141204141205141206141207141208141209141210141211141212141213141214141215141216141217141218141219141220141221141222141223141224141225141226141227141228141229141230141231141232141233141234141235141236141237141238141239141240141241141242141243141244141245141246141247141248141249141250141251141252141253141254141255141256141257141258141259141260141261141262141263141264141265141266141267141268141269141270141271141272141273141274141275141276141277141278141279141280141281141282141283141284141285141286141287141288141289141290141291141292141293141294141295141296141297141298141299141300141301141302141303141304141305141306141307141308141309141310141311141312141313141314141315141316141317141318141319141320141321141322141323141324141325141326141327141328141329141330141331141332141333141334141335141336141337141338141339141340141341141342141343141344141345141346141347141348141349141350141351141352141353141354141355141356141357141358141359141360141361141362141363141364141365141366141367141368141369141370141371141372141373141374141375141376141377141378141379141380141381141382141383141384141385141386141387141388141389141390141391141392141393141394141395141396141397141398141399141400141401141402141403141404141405141406141407141408141409141410141411141412141413141414141415141416141417141418141419141420141421141422141423141424141425141426141427141428141429141430141431141432141433141434141435141436141437141438141439141440141441141442141443141444141445141446141447141448141449141450141451141452141453141454141455141456141457141458141459141460141461141462141463141464141465141466141467141468141469141470141471141472141473141474141475141476141477141478141479141480141481141482141483141484141485141486141487141488141489141490141491141492141493141494141495141496141497141498141499141500141501141502141503141504141505141506141507141508141509141510141511141512141513141514141515141516141517141518141519141520141521141522141523141524141525141526141527141528141529141530141531141532141533141534141535141536141537141538141539141540141541141542141543141544141545141546141547141548141549141550141551141552141553141554141555141556141557141558141559141560141561141562141563141564141565141566141567141568141569141570141571141572141573141574141575141576141577141578141579141580141581141582141583141584141585141586141587141588141589141590141591141592141593141594141595141596141597141598141599141600141601141602141603141604141605141606141607141608141609141610141611141612141613141614141615141616141617141618141619141620141621141622141623141624141625141626141627141628141629141630141631141632141633141634141635141636141637141638141639141640141641141642141643141644141645141646141647141648141649141650141651141652141653141654141655141656141657141658141659141660141661141662141663141664141665141666141667141668141669141670141671141672141673141674141675141676141677141678141679141680141681141682141683141684141685141686141687141688141689141690141691141692141693141694141695141696141697141698141699141700141701141702141703141704141705141706141707141708141709141710141711141712141713141714141715141716141717141718141719141720141721141722141723141724141725141726141727141728141729141730141731141732141733141734141735141736141737141738141739141740141741141742141743141744141745141746141747141748141749141750141751141752141753141754141755141756141757141758141759141760141761141762141763141764141765141766141767141768141769141770141771141772141773141774141775141776141777141778141779141780141781141782141783141784141785141786141787141788141789141790141791141792141793141794141795141796141797141798141799141800141801141802141803141804141805141806141807141808141809141810141811141812141813141814141815141816141817141818141819141820141821141822141823141824141825141826141827141828141829141830141831141832141833141834141835141836141837141838141839141840141841141842141843141844141845141846141847141848141849141850141851141852141853141854141855141856141857141858141859141860141861141862141863141864141865141866141867141868141869141870141871141872141873141874141875141876141877141878141879141880141881141882141883141884141885141886141887141888141889141890141891141892141893141894141895141896141897141898141899141900141901141902141903141904141905141906141907141908141909141910141911141912141913141914141915141916141917141918141919141920141921141922141923141924141925141926141927141928141929141930141931141932141933141934141935141936141937141938141939141940141941141942141943141944141945141946141947141948141949141950141951141952141953141954141955141956141957141958141959141960141961141962141963141964141965141966141967141968141969141970141971141972141973141974141975141976141977141978141979141980141981141982141983141984141985141986141987141988141989141990141991141992141993141994141995141996141997141998141999142000142001142002142003142004142005142006142007142008142009142010142011142012142013142014142015142016142017142018142019142020142021142022142023142024142025142026142027142028142029142030142031142032142033142034142035142036142037142038142039142040142041142042142043142044142045142046142047142048142049142050142051142052142053142054142055142056142057142058142059142060142061142062142063142064142065142066142067142068142069142070142071142072142073142074142075142076142077142078142079142080142081142082142083142084142085142086142087142088142089142090142091142092142093142094142095142096142097142098142099142100142101142102142103142104142105142106142107142108142109142110142111142112142113142114142115142116142117142118142119142120142121142122142123142124142125142126142127142128142129142130142131142132142133142134142135142136142137142138142139142140142141142142142143142144142145142146142147142148142149142150142151142152142153142154142155142156142157142158142159142160142161142162142163142164142165142166142167142168142169142170142171142172142173142174142175142176142177142178142179142180142181142182142183142184142185142186142187142188142189142190142191142192142193142194142195142196142197142198142199142200142201142202142203142204142205142206142207142208142209142210142211142212142213142214142215142216142217142218142219142220142221142222142223142224142225142226142227142228142229142230142231142232142233142234142235142236142237142238142239142240142241142242142243142244142245142246142247142248142249142250142251142252142253142254142255142256142257142258142259142260142261142262142263142264142265142266142267142268142269142270142271142272142273142274142275142276142277142278142279142280142281142282142283142284142285142286142287142288142289142290142291142292142293142294142295142296142297142298142299142300142301142302142303142304142305142306142307142308142309142310142311142312142313142314142315142316142317142318142319142320142321142322142323142324142325142326142327142328142329142330142331142332142333142334142335142336142337142338142339142340142341142342142343142344142345142346142347142348142349142350142351142352142353142354142355142356142357142358142359142360142361142362142363142364142365142366142367142368142369142370142371142372142373142374142375142376142377142378142379142380142381142382142383142384142385142386142387142388142389142390142391142392142393142394142395142396142397142398142399142400142401142402142403142404142405142406142407142408142409142410142411142412142413142414142415142416142417142418142419142420142421142422142423142424142425142426142427142428142429142430142431142432142433142434142435142436142437142438142439142440142441142442142443142444142445142446142447142448142449142450142451142452142453142454142455142456142457142458142459142460142461142462142463142464142465142466142467142468142469142470142471142472142473142474142475142476142477142478142479142480142481142482142483142484142485142486142487142488142489142490142491142492142493142494142495142496142497142498142499142500142501142502142503142504142505142506142507142508142509142510142511142512142513142514142515142516142517142518142519142520142521142522142523142524142525142526142527142528142529142530142531142532142533142534142535142536142537142538142539142540142541142542142543142544142545142546142547142548142549142550142551142552142553142554142555142556142557142558142559142560142561142562142563142564142565142566142567142568142569142570142571142572142573142574142575142576142577142578142579142580142581142582142583142584142585142586142587142588142589142590142591142592142593142594142595142596142597142598142599142600142601142602142603142604142605142606142607142608142609142610142611142612142613142614142615142616142617142618142619142620142621142622142623142624142625142626142627142628142629142630142631142632142633142634142635142636142637142638142639142640142641142642142643142644142645142646142647142648142649142650142651142652142653142654142655142656142657142658142659142660142661142662142663142664142665142666142667142668142669142670142671142672142673142674142675142676142677142678142679142680142681142682142683142684142685142686142687142688142689142690142691142692142693142694142695142696142697142698142699142700142701142702142703142704142705142706142707142708142709142710142711142712142713142714142715142716142717142718142719142720142721142722142723142724142725142726142727142728142729142730142731142732142733142734142735142736142737142738142739142740142741142742142743142744142745142746142747142748142749142750142751142752142753142754142755142756142757142758142759142760142761142762142763142764142765142766142767142768142769142770142771142772142773142774142775142776142777142778142779142780142781142782142783142784142785142786142787142788142789142790142791142792142793142794142795142796142797142798142799142800142801142802142803142804142805142806142807142808142809142810142811142812142813142814142815142816142817142818142819142820142821142822142823142824142825142826142827142828142829142830142831142832142833142834142835142836142837142838142839142840142841142842142843142844142845142846142847142848142849142850142851142852142853142854142855142856142857142858142859142860142861142862142863142864142865142866142867142868142869142870142871142872142873142874142875142876142877142878142879142880142881142882142883142884142885142886142887142888142889142890142891142892142893142894142895142896142897142898142899142900142901142902142903142904142905142906142907142908142909142910142911142912142913142914142915142916142917142918142919142920142921142922142923142924142925142926142927142928142929142930142931142932142933142934142935142936142937142938142939142940142941142942142943142944142945142946142947142948142949142950142951142952142953142954142955142956142957142958142959142960142961142962142963142964142965142966142967142968142969142970142971142972142973142974142975142976142977142978142979142980142981142982142983142984142985142986142987142988142989142990142991142992142993142994142995142996142997142998142999143000143001143002143003143004143005143006143007143008143009143010143011143012143013143014143015143016143017143018143019143020143021143022143023143024143025143026143027143028143029143030143031143032143033143034143035143036143037143038143039143040143041143042143043143044143045143046143047143048143049143050143051143052143053143054143055143056143057143058143059143060143061143062143063143064143065143066143067143068143069143070143071143072143073143074143075143076143077143078143079143080143081143082143083143084143085143086143087143088143089143090143091143092143093143094143095143096143097143098143099143100143101143102143103143104143105143106143107143108143109143110143111143112143113143114143115143116143117143118143119143120143121143122143123143124143125143126143127143128143129143130143131143132143133143134143135143136143137143138143139143140143141143142143143143144143145143146143147143148143149143150143151143152143153143154143155143156143157143158143159143160143161143162143163143164143165143166143167143168143169143170143171143172143173143174143175143176143177143178143179143180143181143182143183143184143185143186143187143188143189143190143191143192143193143194143195143196143197143198143199143200143201143202143203143204143205143206143207143208143209143210143211143212143213143214143215143216143217143218143219143220143221143222143223143224143225143226143227143228143229143230143231143232143233143234143235143236143237143238143239143240143241143242143243143244143245143246143247143248143249143250143251143252143253143254143255143256143257143258143259143260143261143262143263143264143265143266143267143268143269143270143271143272143273143274143275143276143277143278143279143280143281143282143283143284143285143286143287143288143289143290143291143292143293143294143295143296143297143298143299143300143301143302143303143304143305143306143307143308143309143310143311143312143313143314143315143316143317143318143319143320143321143322143323143324143325143326143327143328143329143330143331143332143333143334143335143336143337143338143339143340143341143342143343143344143345143346143347143348143349143350143351143352143353143354143355143356143357143358143359143360143361143362143363143364143365143366143367143368143369143370143371143372143373143374143375143376143377143378143379143380143381143382143383143384143385143386143387143388143389143390143391143392143393143394143395143396143397143398143399143400143401143402143403143404143405143406143407143408143409143410143411143412143413143414143415143416143417143418143419143420143421143422143423143424143425143426143427143428143429143430143431143432143433143434143435143436143437143438143439143440143441143442143443143444143445143446143447143448143449143450143451143452143453143454143455143456143457143458143459143460143461143462143463143464143465143466143467143468143469143470143471143472143473143474143475143476143477143478143479143480143481143482143483143484143485143486143487143488143489143490143491143492143493143494143495143496143497143498143499143500143501143502143503143504143505143506143507143508143509143510143511143512143513143514143515143516143517143518143519143520143521143522143523143524143525143526143527143528143529143530143531143532143533143534143535143536143537143538143539143540143541143542143543143544143545143546143547143548143549143550143551143552143553143554143555143556143557143558143559143560143561143562143563143564143565143566143567143568143569143570143571143572143573143574143575143576143577143578143579143580143581143582143583143584143585143586143587143588143589143590143591143592143593143594143595143596143597143598143599143600143601143602143603143604143605143606143607143608143609143610143611143612143613143614143615143616143617143618143619143620143621143622143623143624143625143626143627143628143629143630143631143632143633143634143635143636143637143638143639143640143641143642143643143644143645143646143647143648143649143650143651143652143653143654143655143656143657143658143659143660143661143662143663143664143665143666143667143668143669143670143671143672143673143674143675143676143677143678143679143680143681143682143683143684143685143686143687143688143689143690143691143692143693143694143695143696143697143698143699143700143701143702143703143704143705143706143707143708143709143710143711143712143713143714143715143716143717143718143719143720143721143722143723143724143725143726143727143728143729143730143731143732143733143734143735143736143737143738143739143740143741143742143743143744143745143746143747143748143749143750143751143752143753143754143755143756143757143758143759143760143761143762143763143764143765143766143767143768143769143770143771143772143773143774143775143776143777143778143779143780143781143782143783143784143785143786143787143788143789143790143791143792143793143794143795143796143797143798143799143800143801143802143803143804143805143806143807143808143809143810143811143812143813143814143815143816143817143818143819143820143821143822143823143824143825143826143827143828143829143830143831143832143833143834143835143836143837143838143839143840143841143842143843143844143845143846143847143848143849143850143851143852143853143854143855143856143857143858143859143860143861143862143863143864143865143866143867143868143869143870143871143872143873143874143875143876143877143878143879143880143881143882143883143884143885143886143887143888143889143890143891143892143893143894143895143896143897143898143899143900143901143902143903143904143905143906143907143908143909143910143911143912143913143914143915143916143917143918143919143920143921143922143923143924143925143926143927143928143929143930143931143932143933143934143935143936143937143938143939143940143941143942143943143944143945143946143947143948143949143950143951143952143953143954143955143956143957143958143959143960143961143962143963143964143965143966143967143968143969143970143971143972143973143974143975143976143977143978143979143980143981143982143983143984143985143986143987143988143989143990143991143992143993143994143995143996143997143998143999144000144001144002144003144004144005144006144007144008144009144010144011144012144013144014144015144016144017144018144019144020144021144022144023144024144025144026144027144028144029144030144031144032144033144034144035144036144037144038144039144040144041144042144043144044144045144046144047144048144049144050144051144052144053144054144055144056144057144058144059144060144061144062144063144064144065144066144067144068144069144070144071144072144073144074144075144076144077144078144079144080144081144082144083144084144085144086144087144088144089144090144091144092144093144094144095144096144097144098144099144100144101144102144103144104144105144106144107144108144109144110144111144112144113144114144115144116144117144118144119144120144121144122144123144124144125144126144127144128144129144130144131144132144133144134144135144136144137144138144139144140144141144142144143144144144145144146144147144148144149144150144151144152144153144154144155144156144157144158144159144160144161144162144163144164144165144166144167144168144169144170144171144172144173144174144175144176144177144178144179144180144181144182144183144184144185144186144187144188144189144190144191144192144193144194144195144196144197144198144199144200144201144202144203144204144205144206144207144208144209144210144211144212144213144214144215144216144217144218144219144220144221144222144223144224144225144226144227144228144229144230144231144232144233144234144235144236144237144238144239144240144241144242144243144244144245144246144247144248144249144250144251144252144253144254144255144256144257144258144259144260144261144262144263144264144265144266144267144268144269144270144271144272144273144274144275144276144277144278144279144280144281144282144283144284144285144286144287144288144289144290144291144292144293144294144295144296144297144298144299144300144301144302144303144304144305144306144307144308144309144310144311144312144313144314144315144316144317144318144319144320144321144322144323144324144325144326144327144328144329144330144331144332144333144334144335144336144337144338144339144340144341144342144343144344144345144346144347144348144349144350144351144352144353144354144355144356144357144358144359144360144361144362144363144364144365144366144367144368144369144370144371144372144373144374144375144376144377144378144379144380144381144382144383144384144385144386144387144388144389144390144391144392144393144394144395144396144397144398144399144400144401144402144403144404144405144406144407144408144409144410144411144412144413144414144415144416144417144418144419144420144421144422144423144424144425144426144427144428144429144430144431144432144433144434144435144436144437144438144439144440144441144442144443144444144445144446144447144448144449144450144451144452144453144454144455144456144457144458144459144460144461144462144463144464144465144466144467144468144469144470144471144472144473144474144475144476144477144478144479144480144481144482144483144484144485144486144487144488144489144490144491144492144493144494144495144496144497144498144499144500144501144502144503144504144505144506144507144508144509144510144511144512144513144514144515144516144517144518144519144520144521144522144523144524144525144526144527144528144529144530144531144532144533144534144535144536144537144538144539144540144541144542144543144544144545144546144547144548144549144550144551144552144553144554144555144556144557144558144559144560144561144562144563144564144565144566144567144568144569144570144571144572144573144574144575144576144577144578144579144580144581144582144583144584144585144586144587144588144589144590144591144592144593144594144595144596144597144598144599144600144601144602144603144604144605144606144607144608144609144610144611144612144613144614144615144616144617144618144619144620144621144622144623144624144625144626144627144628144629144630144631144632144633144634144635144636144637144638144639144640144641144642144643144644144645144646144647144648144649144650144651144652144653144654144655144656144657144658144659144660144661144662144663144664144665144666144667144668144669144670144671144672144673144674144675144676144677144678144679144680144681144682144683144684144685144686144687144688144689144690144691144692144693144694144695144696144697144698144699144700144701144702144703144704144705144706144707144708144709144710144711144712144713144714144715144716144717144718144719144720144721144722144723144724144725144726144727144728144729144730144731144732144733144734144735144736144737144738144739144740144741144742144743144744144745144746144747144748144749144750144751144752144753144754144755144756144757144758144759144760144761144762144763144764144765144766144767144768144769144770144771144772144773144774144775144776144777144778144779144780144781144782144783144784144785144786144787144788144789144790144791144792144793144794144795144796144797144798144799144800144801144802144803144804144805144806144807144808144809144810144811144812144813144814144815144816144817144818144819144820144821144822144823144824144825144826144827144828144829144830144831144832144833144834144835144836144837144838144839144840144841144842144843144844144845144846144847144848144849144850144851144852144853144854144855144856144857144858144859144860144861144862144863144864144865144866144867144868144869144870144871144872144873144874144875144876144877144878144879144880144881144882144883144884144885144886144887144888144889144890144891144892144893144894144895144896144897144898144899144900144901144902144903144904144905144906144907144908144909144910144911144912144913144914144915144916144917144918144919144920144921144922144923144924144925144926144927144928144929144930144931144932144933144934144935144936144937144938144939144940144941144942144943144944144945144946144947144948144949144950144951144952144953144954144955144956144957144958144959144960144961144962144963144964144965144966144967144968144969144970144971144972144973144974144975144976144977144978144979144980144981144982144983144984144985144986144987144988144989144990144991144992144993144994144995144996144997144998144999145000145001145002145003145004145005145006145007145008145009145010145011145012145013145014145015145016145017145018145019145020145021145022145023145024145025145026145027145028145029145030145031145032145033145034145035145036145037145038145039145040145041145042145043145044145045145046145047145048145049145050145051145052145053145054145055145056145057145058145059145060145061145062145063145064145065145066145067145068145069145070145071145072145073145074145075145076145077145078145079145080145081145082145083145084145085145086145087145088145089145090145091145092145093145094145095145096145097145098145099145100145101145102145103145104145105145106145107145108145109145110145111145112145113145114145115145116145117145118145119145120145121145122145123145124145125145126145127145128145129145130145131145132145133145134145135145136145137145138145139145140145141145142145143145144145145145146145147145148145149145150145151145152145153145154145155145156145157145158145159145160145161145162145163145164145165145166145167145168145169145170145171145172145173145174145175145176145177145178145179145180145181145182145183145184145185145186145187145188145189145190145191145192145193145194145195145196145197145198145199145200145201145202145203145204145205145206145207145208145209145210145211145212145213145214145215145216145217145218145219145220145221145222145223145224145225145226145227145228145229145230145231145232145233145234145235145236145237145238145239145240145241145242145243145244145245145246145247145248145249145250145251145252145253145254145255145256145257145258145259145260145261145262145263145264145265145266145267145268145269145270145271145272145273145274145275145276145277145278145279145280145281145282145283145284145285145286145287145288145289145290145291145292145293145294145295145296145297145298145299145300145301145302145303145304145305145306145307145308145309145310145311145312145313145314145315145316145317145318145319145320145321145322145323145324145325145326145327145328145329145330145331145332145333145334145335145336145337145338145339145340145341145342145343145344145345145346145347145348145349145350145351145352145353145354145355145356145357145358145359145360145361145362145363145364145365145366145367145368145369145370145371145372145373145374145375145376145377145378145379145380145381145382145383145384145385145386145387145388145389145390145391145392145393145394145395145396145397145398145399145400145401145402145403145404145405145406145407145408145409145410145411145412145413145414145415145416145417145418145419145420145421145422145423145424145425145426145427145428145429145430145431145432145433145434145435145436145437145438145439145440145441145442145443145444145445145446145447145448145449145450145451145452145453145454145455145456145457145458145459145460145461145462145463145464145465145466145467145468145469145470145471145472145473145474145475145476145477145478145479145480145481145482145483145484145485145486145487145488145489145490145491145492145493145494145495145496145497145498145499145500145501145502145503145504145505145506145507145508145509145510145511145512145513145514145515145516145517145518145519145520145521145522145523145524145525145526145527145528145529145530145531145532145533145534145535145536145537145538145539145540145541145542145543145544145545145546145547145548145549145550145551145552145553145554145555145556145557145558145559145560145561145562145563145564145565145566145567145568145569145570145571145572145573145574145575145576145577145578145579145580145581145582145583145584145585145586145587145588145589145590145591145592145593145594145595145596145597145598145599145600145601145602145603145604145605145606145607145608145609145610145611145612145613145614145615145616145617145618145619145620145621145622145623145624145625145626145627145628145629145630145631145632145633145634145635145636145637145638145639145640145641145642145643145644145645145646145647145648145649145650145651145652145653145654145655145656145657145658145659145660145661145662145663145664145665145666145667145668145669145670145671145672145673145674145675145676145677145678145679145680145681145682145683145684145685145686145687145688145689145690145691145692145693145694145695145696145697145698145699145700145701145702145703145704145705145706145707145708145709145710145711145712145713145714145715145716145717145718145719145720145721145722145723145724145725145726145727145728145729145730145731145732145733145734145735145736145737145738145739145740145741145742145743145744145745145746145747145748145749145750145751145752145753145754145755145756145757145758145759145760145761145762145763145764145765145766145767145768145769145770145771145772145773145774145775145776145777145778145779145780145781145782145783145784145785145786145787145788145789145790145791145792145793145794145795145796145797145798145799145800145801145802145803145804145805145806145807145808145809145810145811145812145813145814145815145816145817145818145819145820145821145822145823145824145825145826145827145828145829145830145831145832145833145834145835145836145837145838145839145840145841145842145843145844145845145846145847145848145849145850145851145852145853145854145855145856145857145858145859145860145861145862145863145864145865145866145867145868145869145870145871145872145873145874145875145876145877145878145879145880145881145882145883145884145885145886145887145888145889145890145891145892145893145894145895145896145897145898145899145900145901145902145903145904145905145906145907145908145909145910145911145912145913145914145915145916145917145918145919145920145921145922145923145924145925145926145927145928145929145930145931145932145933145934145935145936145937145938145939145940145941145942145943145944145945145946145947145948145949145950145951145952145953145954145955145956145957145958145959145960145961145962145963145964145965145966145967145968145969145970145971145972145973145974145975145976145977145978145979145980145981145982145983145984145985145986145987145988145989145990145991145992145993145994145995145996145997145998145999146000146001146002146003146004146005146006146007146008146009146010146011146012146013146014146015146016146017146018146019146020146021146022146023146024146025146026146027146028146029146030146031146032146033146034146035146036146037146038146039146040146041146042146043146044146045146046146047146048146049146050146051146052146053146054146055146056146057146058146059146060146061146062146063146064146065146066146067146068146069146070146071146072146073146074146075146076146077146078146079146080146081146082146083146084146085146086146087146088146089146090146091146092146093146094146095146096146097146098146099146100146101146102146103146104146105146106146107146108146109146110146111146112146113146114146115146116146117146118146119146120146121146122146123146124146125146126146127146128146129146130146131146132146133146134146135146136146137146138146139146140146141146142146143146144146145146146146147146148146149146150146151146152146153146154146155146156146157146158146159146160146161146162146163146164146165146166146167146168146169146170146171146172146173146174146175146176146177146178146179146180146181146182146183146184146185146186146187146188146189146190146191146192146193146194146195146196146197146198146199146200146201146202146203146204146205146206146207146208146209146210146211146212146213146214146215146216146217146218146219146220146221146222146223146224146225146226146227146228146229146230146231146232146233146234146235146236146237146238146239146240146241146242146243146244146245146246146247146248146249146250146251146252146253146254146255146256146257146258146259146260146261146262146263146264146265146266146267146268146269146270146271146272146273146274146275146276146277146278146279146280146281146282146283146284146285146286146287146288146289146290146291146292146293146294146295146296146297146298146299146300146301146302146303146304146305146306146307146308146309146310146311146312146313146314146315146316146317146318146319146320146321146322146323146324146325146326146327146328146329146330146331146332146333146334146335146336146337146338146339146340146341146342146343146344146345146346146347146348146349146350146351146352146353146354146355146356146357146358146359146360146361146362146363146364146365146366146367146368146369146370146371146372146373146374146375146376146377146378146379146380146381146382146383146384146385146386146387146388146389146390146391146392146393146394146395146396146397146398146399146400146401146402146403146404146405146406146407146408146409146410146411146412146413146414146415146416146417146418146419146420146421146422146423146424146425146426146427146428146429146430146431146432146433146434146435146436146437146438146439146440146441146442146443146444146445146446146447146448146449146450146451146452146453146454146455146456146457146458146459146460146461146462146463146464146465146466146467146468146469146470146471146472146473146474146475146476146477146478146479146480146481146482146483146484146485146486146487146488146489146490146491146492146493146494146495146496146497146498146499146500146501146502146503146504146505146506146507146508146509146510146511146512146513146514146515146516146517146518146519146520146521146522146523146524146525146526146527146528146529146530146531146532146533146534146535146536146537146538146539146540146541146542146543146544146545146546146547146548146549146550146551146552146553146554146555146556146557146558146559146560146561146562146563146564146565146566146567146568146569146570146571146572146573146574146575146576146577146578146579146580146581146582146583146584146585146586146587146588146589146590146591146592146593146594146595146596146597146598146599146600146601146602146603146604146605146606146607146608146609146610146611146612146613146614146615146616146617146618146619146620146621146622146623146624146625146626146627146628146629146630146631146632146633146634146635146636146637146638146639146640146641146642146643146644146645146646146647146648146649146650146651146652146653146654146655146656146657146658146659146660146661146662146663146664146665146666146667146668146669146670146671146672146673146674146675146676146677146678146679146680146681146682146683146684146685146686146687146688146689146690146691146692146693146694146695146696146697146698146699146700146701146702146703146704146705146706146707146708146709146710146711146712146713146714146715146716146717146718146719146720146721146722146723146724146725146726146727146728146729146730146731146732146733146734146735146736146737146738146739146740146741146742146743146744146745146746146747146748146749146750146751146752146753146754146755146756146757146758146759146760146761146762146763146764146765146766146767146768146769146770146771146772146773146774146775146776146777146778146779146780146781146782146783146784146785146786146787146788146789146790146791146792146793146794146795146796146797146798146799146800146801146802146803146804146805146806146807146808146809146810146811146812146813146814146815146816146817146818146819146820146821146822146823146824146825146826146827146828146829146830146831146832146833146834146835146836146837146838146839146840146841146842146843146844146845146846146847146848146849146850146851146852146853146854146855146856146857146858146859146860146861146862146863146864146865146866146867146868146869146870146871146872146873146874146875146876146877146878146879146880146881146882146883146884146885146886146887146888146889146890146891146892146893146894146895146896146897146898146899146900146901146902146903146904146905146906146907146908146909146910146911146912146913146914146915146916146917146918146919146920146921146922146923146924146925146926146927146928146929146930146931146932146933146934146935146936146937146938146939146940146941146942146943146944146945146946146947146948146949146950146951146952146953146954146955146956146957146958146959146960146961146962146963146964146965146966146967146968146969146970146971146972146973146974146975146976146977146978146979146980146981146982146983146984146985146986146987146988146989146990146991146992146993146994146995146996146997146998146999147000147001147002147003147004147005147006147007147008147009147010147011147012147013147014147015147016147017147018147019147020147021147022147023147024147025147026147027147028147029147030147031147032147033147034147035147036147037147038147039147040147041147042147043147044147045147046147047147048147049147050147051147052147053147054147055147056147057147058147059147060147061147062147063147064147065147066147067147068147069147070147071147072147073147074147075147076147077147078147079147080147081147082147083147084147085147086147087147088147089147090147091147092147093147094147095147096147097147098147099147100147101147102147103147104147105147106147107147108147109147110147111147112147113147114147115147116147117147118147119147120147121147122147123147124147125147126147127147128147129147130147131147132147133147134147135147136147137147138147139147140147141147142147143147144147145147146147147147148147149147150147151147152147153147154147155147156147157147158147159147160147161147162147163147164147165147166147167147168147169147170147171147172147173147174147175147176147177147178147179147180147181147182147183147184147185147186147187147188147189147190147191147192147193147194147195147196147197147198147199147200147201147202147203147204147205147206147207147208147209147210147211147212147213147214147215147216147217147218147219147220147221147222147223147224147225147226147227147228147229147230147231147232147233147234147235147236147237147238147239147240147241147242147243147244147245147246147247147248147249147250147251147252147253147254147255147256147257147258147259147260147261147262147263147264147265147266147267147268147269147270147271147272147273147274147275147276147277147278147279147280147281147282147283147284147285147286147287147288147289147290147291147292147293147294147295147296147297147298147299147300147301147302147303147304147305147306147307147308147309147310147311147312147313147314147315147316147317147318147319147320147321147322147323147324147325147326147327147328147329147330147331147332147333147334147335147336147337147338147339147340147341147342147343147344147345147346147347147348147349147350147351147352147353147354147355147356147357147358147359147360147361147362147363147364147365147366147367147368147369147370147371147372147373147374147375147376147377147378147379147380147381147382147383147384147385147386147387147388147389147390147391147392147393147394147395147396147397147398147399147400147401147402147403147404147405147406147407147408147409147410147411147412147413147414147415147416147417147418147419147420147421147422147423147424147425147426147427147428147429147430147431147432147433147434147435147436147437147438147439147440147441147442147443147444147445147446147447147448147449147450147451147452147453147454147455147456147457147458147459147460147461147462147463147464147465147466147467147468147469147470147471147472147473147474147475147476147477147478147479147480147481147482147483147484147485147486147487147488147489147490147491147492147493147494147495147496147497147498147499147500147501147502147503147504147505147506147507147508147509147510147511147512147513147514147515147516147517147518147519147520147521147522147523147524147525147526147527147528147529147530147531147532147533147534147535147536147537147538147539147540147541147542147543147544147545147546147547147548147549147550147551147552147553147554147555147556147557147558147559147560147561147562147563147564147565147566147567147568147569147570147571147572147573147574147575147576147577147578147579147580147581147582147583147584147585147586147587147588147589147590147591147592147593147594147595147596147597147598147599147600147601147602147603147604147605147606147607147608147609147610147611147612147613147614147615147616147617147618147619147620147621147622147623147624147625147626147627147628147629147630147631147632147633147634147635147636147637147638147639147640147641147642147643147644147645147646147647147648147649147650147651147652147653147654147655147656147657147658147659147660147661147662147663147664147665147666147667147668147669147670147671147672147673147674147675147676147677147678147679147680147681147682147683147684147685147686147687147688147689147690147691147692147693147694147695147696147697147698147699147700147701147702147703147704147705147706147707147708147709147710147711147712147713147714147715147716147717147718147719147720147721147722147723147724147725147726147727147728147729147730147731147732147733147734147735147736147737147738147739147740147741147742147743147744147745147746147747147748147749147750147751147752147753147754147755147756147757147758147759147760147761147762147763147764147765147766147767147768147769147770147771147772147773147774147775147776147777147778147779147780147781147782147783147784147785147786147787147788147789147790147791147792147793147794147795147796147797147798147799147800147801147802147803147804147805147806147807147808147809147810147811147812147813147814147815147816147817147818147819147820147821147822147823147824147825147826147827147828147829147830147831147832147833147834147835147836147837147838147839147840147841147842147843147844147845147846147847147848147849147850147851147852147853147854147855147856147857147858147859147860147861147862147863147864147865147866147867147868147869147870147871147872147873147874147875147876147877147878147879147880147881147882147883147884147885147886147887147888147889147890147891147892147893147894147895147896147897147898147899147900147901147902147903147904147905147906147907147908147909147910147911147912147913147914147915147916147917147918147919147920147921147922147923147924147925147926147927147928147929147930147931147932147933147934147935147936147937147938147939147940147941147942147943147944147945147946147947147948147949147950147951147952147953147954147955147956147957147958147959147960147961147962147963147964147965147966147967147968147969147970147971147972147973147974147975147976147977147978147979147980147981147982147983147984147985147986147987147988147989147990147991147992147993147994147995147996147997147998147999148000148001148002148003148004148005148006148007148008148009148010148011148012148013148014148015148016148017148018148019148020148021148022148023148024148025148026148027148028148029148030148031148032148033148034148035148036148037148038148039148040148041148042148043148044148045148046148047148048148049148050148051148052148053148054148055148056148057148058148059148060148061148062148063148064148065148066148067148068148069148070148071148072148073148074148075148076148077148078148079148080148081148082148083148084148085148086148087148088148089148090148091148092148093148094148095148096148097148098148099148100148101148102148103148104148105148106148107148108148109148110148111148112148113148114148115148116148117148118148119148120148121148122148123148124148125148126148127148128148129148130148131148132148133148134148135148136148137148138148139148140148141148142148143148144148145148146148147148148148149148150148151148152148153148154148155148156148157148158148159148160148161148162148163148164148165148166148167148168148169148170148171148172148173148174148175148176148177148178148179148180148181148182148183148184148185148186148187148188148189148190148191148192148193148194148195148196148197148198148199148200148201148202148203148204148205148206148207148208148209148210148211148212148213148214148215148216148217148218148219148220148221148222148223148224148225148226148227148228148229148230148231148232148233148234148235148236148237148238148239148240148241148242148243148244148245148246148247148248148249148250148251148252148253148254148255148256148257148258148259148260148261148262148263148264148265148266148267148268148269148270148271148272148273148274148275148276148277148278148279148280148281148282148283148284148285148286148287148288148289148290148291148292148293148294148295148296148297148298148299148300148301148302148303148304148305148306148307148308148309148310148311148312148313148314148315148316148317148318148319148320148321148322148323148324148325148326148327148328148329148330148331148332148333148334148335148336148337148338148339148340148341148342148343148344148345148346148347148348148349148350148351148352148353148354148355148356148357148358148359148360148361148362148363148364148365148366148367148368148369148370148371148372148373148374148375148376148377148378148379148380148381148382148383148384148385148386148387148388148389148390148391148392148393148394148395148396148397148398148399148400148401148402148403148404148405148406148407148408148409148410148411148412148413148414148415148416148417148418148419148420148421148422148423148424148425148426148427148428148429148430148431148432148433148434148435148436148437148438148439148440148441148442148443148444148445148446148447148448148449148450148451148452148453148454148455148456148457148458148459148460148461148462148463148464148465148466148467148468148469148470148471148472148473148474148475148476148477148478148479148480148481148482148483148484148485148486148487148488148489148490148491148492148493148494148495148496148497148498148499148500148501148502148503148504148505148506148507148508148509148510148511148512148513148514148515148516148517148518148519148520148521148522148523148524148525148526148527148528148529148530148531148532148533148534148535148536148537148538148539148540148541148542148543148544148545148546148547148548148549148550148551148552148553148554148555148556148557148558148559148560148561148562148563148564148565148566148567148568148569148570148571148572148573148574148575148576148577148578148579148580148581148582148583148584148585148586148587148588148589148590148591148592148593148594148595148596148597148598148599148600148601148602148603148604148605148606148607148608148609148610148611148612148613148614148615148616148617148618148619148620148621148622148623148624148625148626148627148628148629148630148631148632148633148634148635148636148637148638148639148640148641148642148643148644148645148646148647148648148649148650148651148652148653148654148655148656148657148658148659148660148661148662148663148664148665148666148667148668148669148670148671148672148673148674148675148676148677148678148679148680148681148682148683148684148685148686148687148688148689148690148691148692148693148694148695148696148697148698148699148700148701148702148703148704148705148706148707148708148709148710148711148712148713148714148715148716148717148718148719148720148721148722148723148724148725148726148727148728148729148730148731148732148733148734148735148736148737148738148739148740148741148742148743148744148745148746148747148748148749148750148751148752148753148754148755148756148757148758148759148760148761148762148763148764148765148766148767148768148769148770148771148772148773148774148775148776148777148778148779148780148781148782148783148784148785148786148787148788148789148790148791148792148793148794148795148796148797148798148799148800148801148802148803148804148805148806148807148808148809148810148811148812148813148814148815148816148817148818148819148820148821148822148823148824148825148826148827148828148829148830148831148832148833148834148835148836148837148838148839148840148841148842148843148844148845148846148847148848148849148850148851148852148853148854148855148856148857148858148859148860148861148862148863148864148865148866148867148868148869148870148871148872148873148874148875148876148877148878148879148880148881148882148883148884148885148886148887148888148889148890148891148892148893148894148895148896148897148898148899148900148901148902148903148904148905148906148907148908148909148910148911148912148913148914148915148916148917148918148919148920148921148922148923148924148925148926148927148928148929148930148931148932148933148934148935148936148937148938148939148940148941148942148943148944148945148946148947148948148949148950148951148952148953148954148955148956148957148958148959148960148961148962148963148964148965148966148967148968148969148970148971148972148973148974148975148976148977148978148979148980148981148982148983148984148985148986148987148988148989148990148991148992148993148994148995148996148997148998148999149000149001149002149003149004149005149006149007149008149009149010149011149012149013149014149015149016149017149018149019149020149021149022149023149024149025149026149027149028149029149030149031149032149033149034149035149036149037149038149039149040149041149042149043149044149045149046149047149048149049149050149051149052149053149054149055149056149057149058149059149060149061149062149063149064149065149066149067149068149069149070149071149072149073149074149075149076149077149078149079149080149081149082149083149084149085149086149087149088149089149090149091149092149093149094149095149096149097149098149099149100149101149102149103149104149105149106149107149108149109149110149111149112149113149114149115149116149117149118149119149120149121149122149123149124149125149126149127149128149129149130149131149132149133149134149135149136149137149138149139149140149141149142149143149144149145149146149147149148149149149150149151149152149153149154149155149156149157149158149159149160149161149162149163149164149165149166149167149168149169149170149171149172149173149174149175149176149177149178149179149180149181149182149183149184149185149186149187149188149189149190149191149192149193149194149195149196149197149198149199149200149201149202149203149204149205149206149207149208149209149210149211149212149213149214149215149216149217149218149219149220149221149222149223149224149225149226149227149228149229149230149231149232149233149234149235149236149237149238149239149240149241149242149243149244149245149246149247149248149249149250149251149252149253149254149255149256149257149258149259149260149261149262149263149264149265149266149267149268149269149270149271149272149273149274149275149276149277149278149279149280149281149282149283149284149285149286149287149288149289149290149291149292149293149294149295149296149297149298149299149300149301149302149303149304149305149306149307149308149309149310149311149312149313149314149315149316149317149318149319149320149321149322149323149324149325149326149327149328149329149330149331149332149333149334149335149336149337149338149339149340149341149342149343149344149345149346149347149348149349149350149351149352149353149354149355149356149357149358149359149360149361149362149363149364149365149366149367149368149369149370149371149372149373149374149375149376149377149378149379149380149381149382149383149384149385149386149387149388149389149390149391149392149393149394149395149396149397149398149399149400149401149402149403149404149405149406149407149408149409149410149411149412149413149414149415149416149417149418149419149420149421149422149423149424149425149426149427149428149429149430149431149432149433149434149435149436149437149438149439149440149441149442149443149444149445149446149447149448149449149450149451149452149453149454149455149456149457149458149459149460149461149462149463149464149465149466149467149468149469149470149471149472149473149474149475149476149477149478149479149480149481149482149483149484149485149486149487149488149489149490149491149492149493149494149495149496149497149498149499149500149501149502149503149504149505149506149507149508149509149510149511149512149513149514149515149516149517149518149519149520149521149522149523149524149525149526149527149528149529149530149531149532149533149534149535149536149537149538149539149540149541149542149543149544149545149546149547149548149549149550149551149552149553149554149555149556149557149558149559149560149561149562149563149564149565149566149567149568149569149570149571149572149573149574149575149576149577149578149579149580149581149582149583149584149585149586149587149588149589149590149591149592149593149594149595149596149597149598149599149600149601149602149603149604149605149606149607149608149609149610149611149612149613149614149615149616149617149618149619149620149621149622149623149624149625149626149627149628149629149630149631149632149633149634149635149636149637149638149639149640149641149642149643149644149645149646149647149648149649149650149651149652149653149654149655149656149657149658149659149660149661149662149663149664149665149666149667149668149669149670149671149672149673149674149675149676149677149678149679149680149681149682149683149684149685149686149687149688149689149690149691149692149693149694149695149696149697149698149699149700149701149702149703149704149705149706149707149708149709149710149711149712149713149714149715149716149717149718149719149720149721149722149723149724149725149726149727149728149729149730149731149732149733149734149735149736149737149738149739149740149741149742149743149744149745149746149747149748149749149750149751149752149753149754149755149756149757149758149759149760149761149762149763149764149765149766149767149768149769149770149771149772149773149774149775149776149777149778149779149780149781149782149783149784149785149786149787149788149789149790149791149792149793149794149795149796149797149798149799149800149801149802149803149804149805149806149807149808149809149810149811149812149813149814149815149816149817149818149819149820149821149822149823149824149825149826149827149828149829149830149831149832149833149834149835149836149837149838149839149840149841149842149843149844149845149846149847149848149849149850149851149852149853149854149855149856149857149858149859149860149861149862149863149864149865149866149867149868149869149870149871149872149873149874149875149876149877149878149879149880149881149882149883149884149885149886149887149888149889149890149891149892149893149894149895149896149897149898149899149900149901149902149903149904149905149906149907149908149909149910149911149912149913149914149915149916149917149918149919149920149921149922149923149924149925149926149927149928149929149930149931149932149933149934149935149936149937149938149939149940149941149942149943149944149945149946149947149948149949149950149951149952149953149954149955149956149957149958149959149960149961149962149963149964149965149966149967149968149969149970149971149972149973149974149975149976149977149978149979149980149981149982149983149984149985149986149987149988149989149990149991149992149993149994149995149996149997149998149999150000150001150002150003150004150005150006150007150008150009150010150011150012150013150014150015150016150017150018150019150020150021150022150023150024150025150026150027150028150029150030150031150032150033150034150035150036150037150038150039150040150041150042150043150044150045150046150047150048150049150050150051150052150053150054150055150056150057150058150059150060150061150062150063150064150065150066150067150068150069150070150071150072150073150074150075150076150077150078150079150080150081150082150083150084150085150086150087150088150089150090150091150092150093150094150095150096150097150098150099150100150101150102150103150104150105150106150107150108150109150110150111150112150113150114150115150116150117150118150119150120150121150122150123150124150125150126150127150128150129150130150131150132150133150134150135150136150137150138150139150140150141150142150143150144150145150146150147150148150149150150150151150152150153150154150155150156150157150158150159150160150161150162150163150164150165150166150167150168150169150170150171150172150173150174150175150176150177150178150179150180150181150182150183150184150185150186150187150188150189150190150191150192150193150194150195150196150197150198150199150200150201150202150203150204150205150206150207150208150209150210150211150212150213150214150215150216150217150218150219150220150221150222150223150224150225150226150227150228150229150230150231150232150233150234150235150236150237150238150239150240150241150242150243150244150245150246150247150248150249150250150251150252150253150254150255150256150257150258150259150260150261150262150263150264150265150266150267150268150269150270150271150272150273150274150275150276150277150278150279150280150281150282150283150284150285150286150287150288150289150290150291150292150293150294150295150296150297150298150299150300150301150302150303150304150305150306150307150308150309150310150311150312150313150314150315150316150317150318150319150320150321150322150323150324150325150326150327150328150329150330150331150332150333150334150335150336150337150338150339150340150341150342150343150344150345150346150347150348150349150350150351150352150353150354150355150356150357150358150359150360150361150362150363150364150365150366150367150368150369150370150371150372150373150374150375150376150377150378150379150380150381150382150383150384150385150386150387150388150389150390150391150392150393150394150395150396150397150398150399150400150401150402150403150404150405150406150407150408150409150410150411150412150413150414150415150416150417150418150419150420150421150422150423150424150425150426150427150428150429150430150431150432150433150434150435150436150437150438150439150440150441150442150443150444150445150446150447150448150449150450150451150452150453150454150455150456150457150458150459150460150461150462150463150464150465150466150467150468150469150470150471150472150473150474150475150476150477150478150479150480150481150482150483150484150485150486150487150488150489150490150491150492150493150494150495150496150497150498150499150500150501150502150503150504150505150506150507150508150509150510150511150512150513150514150515150516150517150518150519150520150521150522150523150524150525150526150527150528150529150530150531150532150533150534150535150536150537150538150539150540150541150542150543150544150545150546150547150548150549150550150551150552150553150554150555150556150557150558150559150560150561150562150563150564150565150566150567150568150569150570150571150572150573150574150575150576150577150578150579150580150581150582150583150584150585150586150587150588150589150590150591150592150593150594150595150596150597150598150599150600150601150602150603150604150605150606150607150608150609150610150611150612150613150614150615150616150617150618150619150620150621150622150623150624150625150626150627150628150629150630150631150632150633150634150635150636150637150638150639150640150641150642150643150644150645150646150647150648150649150650150651150652150653150654150655150656150657150658150659150660150661150662150663150664150665150666150667150668150669150670150671150672150673150674150675150676150677150678150679150680150681150682150683150684150685150686150687150688150689150690150691150692150693150694150695150696150697150698150699150700150701150702150703150704150705150706150707150708150709150710150711150712150713150714150715150716150717150718150719150720150721150722150723150724150725150726150727150728150729150730150731150732150733150734150735150736150737150738150739150740150741150742150743150744150745150746150747150748150749150750150751150752150753150754150755150756150757150758150759150760150761150762150763150764150765150766150767150768150769150770150771150772150773150774150775150776150777150778150779150780150781150782150783150784150785150786150787150788150789150790150791150792150793150794150795150796150797150798150799150800150801150802150803150804150805150806150807150808150809150810150811150812150813150814150815150816150817150818150819150820150821150822150823150824150825150826150827150828150829150830150831150832150833150834150835150836150837150838150839150840150841150842150843150844150845150846150847150848150849150850150851150852150853150854150855150856150857150858150859150860150861150862150863150864150865150866150867150868150869150870150871150872150873150874150875150876150877150878150879150880150881150882150883150884150885150886150887150888150889150890150891150892150893150894150895150896150897150898150899150900150901150902150903150904150905150906150907150908150909150910150911150912150913150914150915150916150917150918150919150920150921150922150923150924150925150926150927150928150929150930150931150932150933150934150935150936150937150938150939150940150941150942150943150944150945150946150947150948150949150950150951150952150953150954150955150956150957150958150959150960150961150962150963150964150965150966150967150968150969150970150971150972150973150974150975150976150977150978150979150980150981150982150983150984150985150986150987150988150989150990150991150992150993150994150995150996150997150998150999151000151001151002151003151004151005151006151007151008151009151010151011151012151013151014151015151016151017151018151019151020151021151022151023151024151025151026151027151028151029151030151031151032151033151034151035151036151037151038151039151040151041151042151043151044151045151046151047151048151049151050151051151052151053151054151055151056151057151058151059151060151061151062151063151064151065151066151067151068151069151070151071151072151073151074151075151076151077151078151079151080151081151082151083151084151085151086151087151088151089151090151091151092151093151094151095151096151097151098151099151100151101151102151103151104151105151106151107151108151109151110151111151112151113151114151115151116151117151118151119151120151121151122151123151124151125151126151127151128151129151130151131151132151133151134151135151136151137151138151139151140151141151142151143151144151145151146151147151148151149151150151151151152151153151154151155151156151157151158151159151160151161151162151163151164151165151166151167151168151169151170151171151172151173151174151175151176151177151178151179151180151181151182151183151184151185151186151187151188151189151190151191151192151193151194151195151196151197151198151199151200151201151202151203151204151205151206151207151208151209151210151211151212151213151214151215151216151217151218151219151220151221151222151223151224151225151226151227151228151229151230151231151232151233151234151235151236151237151238151239151240151241151242151243151244151245151246151247151248151249151250151251151252151253151254151255151256151257151258151259151260151261151262151263151264151265151266151267151268151269151270151271151272151273151274151275151276151277151278151279151280151281151282151283151284151285151286151287151288151289151290151291151292151293151294151295151296151297151298151299151300151301151302151303151304151305151306151307151308151309151310151311151312151313151314151315151316151317151318151319151320151321151322151323151324151325151326151327151328151329151330151331151332151333151334151335151336151337151338151339151340151341151342151343151344151345151346151347151348151349151350151351151352151353151354151355151356151357151358151359151360151361151362151363151364151365151366151367151368151369151370151371151372151373151374151375151376151377151378151379151380151381151382151383151384151385151386151387151388151389151390151391151392151393151394151395151396151397151398151399151400151401151402151403151404151405151406151407151408151409151410151411151412151413151414151415151416151417151418151419151420151421151422151423151424151425151426151427151428151429151430151431151432151433151434151435151436151437151438151439151440151441151442151443151444151445151446151447151448151449151450151451151452151453151454151455151456151457151458151459151460151461151462151463151464151465151466151467151468151469151470151471151472151473151474151475151476151477151478151479151480151481151482151483151484151485151486151487151488151489151490151491151492151493151494151495151496151497151498151499151500151501151502151503151504151505151506151507151508151509151510151511151512151513151514151515151516151517151518151519151520151521151522151523151524151525151526151527151528151529151530151531151532151533151534151535151536151537151538151539151540151541151542151543151544151545151546151547151548151549151550151551151552151553151554151555151556151557151558151559151560151561151562151563151564151565151566151567151568151569151570151571151572151573151574151575151576151577151578151579151580151581151582151583151584151585151586151587151588151589151590151591151592151593151594151595151596151597151598151599151600151601151602151603151604151605151606151607151608151609151610151611151612151613151614151615151616151617151618151619151620151621151622151623151624151625151626151627151628151629151630151631151632151633151634151635151636151637151638151639151640151641151642151643151644151645151646151647151648151649151650151651151652151653151654151655151656151657151658151659151660151661151662151663151664151665151666151667151668151669151670151671151672151673151674151675151676151677151678151679151680151681151682151683151684151685151686151687151688151689151690151691151692151693151694151695151696151697151698151699151700151701151702151703151704151705151706151707151708151709151710151711151712151713151714151715151716151717151718151719151720151721151722151723151724151725151726151727151728151729151730151731151732151733151734151735151736151737151738151739151740151741151742151743151744151745151746151747151748151749151750151751151752151753151754151755151756151757151758151759151760151761151762151763151764151765151766151767151768151769151770151771151772151773151774151775151776151777151778151779151780151781151782151783151784151785151786151787151788151789151790151791151792151793151794151795151796151797151798151799151800151801151802151803151804151805151806151807151808151809151810151811151812151813151814151815151816151817151818151819151820151821151822151823151824151825151826151827151828151829151830151831151832151833151834151835151836151837151838151839151840151841151842151843151844151845151846151847151848151849151850151851151852151853151854151855151856151857151858151859151860151861151862151863151864151865151866151867151868151869151870151871151872151873151874151875151876151877151878151879151880151881151882151883151884151885151886151887151888151889151890151891151892151893151894151895151896151897151898151899151900151901151902151903151904151905151906151907151908151909151910151911151912151913151914151915151916151917151918151919151920151921151922151923151924151925151926151927151928151929151930151931151932151933151934151935151936151937151938151939151940151941151942151943151944151945151946151947151948151949151950151951151952151953151954151955151956151957151958151959151960151961151962151963151964151965151966151967151968151969151970151971151972151973151974151975151976151977151978151979151980151981151982151983151984151985151986151987151988151989151990151991151992151993151994151995151996151997151998151999152000152001152002152003152004152005152006152007152008152009152010152011152012152013152014152015152016152017152018152019152020152021152022152023152024152025152026152027152028152029152030152031152032152033152034152035152036152037152038152039152040152041152042152043152044152045152046152047152048152049152050152051152052152053152054152055152056152057152058152059152060152061152062152063152064152065152066152067152068152069152070152071152072152073152074152075152076152077152078152079152080152081152082152083152084152085152086152087152088152089152090152091152092152093152094152095152096152097152098152099152100152101152102152103152104152105152106152107152108152109152110152111152112152113152114152115152116152117152118152119152120152121152122152123152124152125152126152127152128152129152130152131152132152133152134152135152136152137152138152139152140152141152142152143152144152145152146152147152148152149152150152151152152152153152154152155152156152157152158152159152160152161152162152163152164152165152166152167152168152169152170152171152172152173152174152175152176152177152178152179152180152181152182152183152184152185152186152187152188152189152190152191152192152193152194152195152196152197152198152199152200152201152202152203152204152205152206152207152208152209152210152211152212152213152214152215152216152217152218152219152220152221152222152223152224152225152226152227152228152229152230152231152232152233152234152235152236152237152238152239152240152241152242152243152244152245152246152247152248152249152250152251152252152253152254152255152256152257152258152259152260152261152262152263152264152265152266152267152268152269152270152271152272152273152274152275152276152277152278152279152280152281152282152283152284152285152286152287152288152289152290152291152292152293152294152295152296152297152298152299152300152301152302152303152304152305152306152307152308152309152310152311152312152313152314152315152316152317152318152319152320152321152322152323152324152325152326152327152328152329152330152331152332152333152334152335152336152337152338152339152340152341152342152343152344152345152346152347152348152349152350152351152352152353152354152355152356152357152358152359152360152361152362152363152364152365152366152367152368152369152370152371152372152373152374152375152376152377152378152379152380152381152382152383152384152385152386152387152388152389152390152391152392152393152394152395152396152397152398152399152400152401152402152403152404152405152406152407152408152409152410152411152412152413152414152415152416152417152418152419152420152421152422152423152424152425152426152427152428152429152430152431152432152433152434152435152436152437152438152439152440152441152442152443152444152445152446152447152448152449152450152451152452152453152454152455152456152457152458152459152460152461152462152463152464152465152466152467152468152469152470152471152472152473152474152475152476152477152478152479152480152481152482152483152484152485152486152487152488152489152490152491152492152493152494152495152496152497152498152499152500152501152502152503152504152505152506152507152508152509152510152511152512152513152514152515152516152517152518152519152520152521152522152523152524152525152526152527152528152529152530152531152532152533152534152535152536152537152538152539152540152541152542152543152544152545152546152547152548152549152550152551152552152553152554152555152556152557152558152559152560152561152562152563152564152565152566152567152568152569152570152571152572152573152574152575152576152577152578152579152580152581152582152583152584152585152586152587152588152589152590152591152592152593152594152595152596152597152598152599152600152601152602152603152604152605152606152607152608152609152610152611152612152613152614152615152616152617152618152619152620152621152622152623152624152625152626152627152628152629152630152631152632152633152634152635152636152637152638152639152640152641152642152643152644152645152646152647152648152649152650152651152652152653152654152655152656152657152658152659152660152661152662152663152664152665152666152667152668152669152670152671152672152673152674152675152676152677152678152679152680152681152682152683152684152685152686152687152688152689152690152691152692152693152694152695152696152697152698152699152700152701152702152703152704152705152706152707152708152709152710152711152712152713152714152715152716152717152718152719152720152721152722152723152724152725152726152727152728152729152730152731152732152733152734152735152736152737152738152739152740152741152742152743152744152745152746152747152748152749152750152751152752152753152754152755152756152757152758152759152760152761152762152763152764152765152766152767152768152769152770152771152772152773152774152775152776152777152778152779152780152781152782152783152784152785152786152787152788152789152790152791152792152793152794152795152796152797152798152799152800152801152802152803152804152805152806152807152808152809152810152811152812152813152814152815152816152817152818152819152820152821152822152823152824152825152826152827152828152829152830152831152832152833152834152835152836152837152838152839152840152841152842152843152844152845152846152847152848152849152850152851152852152853152854152855152856152857152858152859152860152861152862152863152864152865152866152867152868152869152870152871152872152873152874152875152876152877152878152879152880152881152882152883152884152885152886152887152888152889152890152891152892152893152894152895152896152897152898152899152900152901152902152903152904152905152906152907152908152909152910152911152912152913152914152915152916152917152918152919152920152921152922152923152924152925152926152927152928152929152930152931152932152933152934152935152936152937152938152939152940152941152942152943152944152945152946152947152948152949152950152951152952152953152954152955152956152957152958152959152960152961152962152963152964152965152966152967152968152969152970152971152972152973152974152975152976152977152978152979152980152981152982152983152984152985152986152987152988152989152990152991152992152993152994152995152996152997152998152999153000153001153002153003153004153005153006153007153008153009153010153011153012153013153014153015153016153017153018153019153020153021153022153023153024153025153026153027153028153029153030153031153032153033153034153035153036153037153038153039153040153041153042153043153044153045153046153047153048153049153050153051153052153053153054153055153056153057153058153059153060153061153062153063153064153065153066153067153068153069153070153071153072153073153074153075153076153077153078153079153080153081153082153083153084153085153086153087153088153089153090153091153092153093153094153095153096153097153098153099153100153101153102153103153104153105153106153107153108153109153110153111153112153113153114153115153116153117153118153119153120153121153122153123153124153125153126153127153128153129153130153131153132153133153134153135153136153137153138153139153140153141153142153143153144153145153146153147153148153149153150153151153152153153153154153155153156153157153158153159153160153161153162153163153164153165153166153167153168153169153170153171153172153173153174153175153176153177153178153179153180153181153182153183153184153185153186153187153188153189153190153191153192153193153194153195153196153197153198153199153200153201153202153203153204153205153206153207153208153209153210153211153212153213153214153215153216153217153218153219153220153221153222153223153224153225153226153227153228153229153230153231153232153233153234153235153236153237153238153239153240153241153242153243153244153245153246153247153248153249153250153251153252153253153254153255153256153257153258153259153260153261153262153263153264153265153266153267153268153269153270153271153272153273153274153275153276153277153278153279153280153281153282153283153284153285153286153287153288153289153290153291153292153293153294153295153296153297153298153299153300153301153302153303153304153305153306153307153308153309153310153311153312153313153314153315153316153317153318153319153320153321153322153323153324153325153326153327153328153329153330153331153332153333153334153335153336153337153338153339153340153341153342153343153344153345153346153347153348153349153350153351153352153353153354153355153356153357153358153359153360153361153362153363153364153365153366153367153368153369153370153371153372153373153374153375153376153377153378153379153380153381153382153383153384153385153386153387153388153389153390153391153392153393153394153395153396153397153398153399153400153401153402153403153404153405153406153407153408153409153410153411153412153413153414153415153416153417153418153419153420153421153422153423153424153425153426153427153428153429153430153431153432153433153434153435153436153437153438153439153440153441153442153443153444153445153446153447153448153449153450153451153452153453153454153455153456153457153458153459153460153461153462153463153464153465153466153467153468153469153470153471153472153473153474153475153476153477153478153479153480153481153482153483153484153485153486153487153488153489153490153491153492153493153494153495153496153497153498153499153500153501153502153503153504153505153506153507153508153509153510153511153512153513153514153515153516153517153518153519153520153521153522153523153524153525153526153527153528153529153530153531153532153533153534153535153536153537153538153539153540153541153542153543153544153545153546153547153548153549153550153551153552153553153554153555153556153557153558153559153560153561153562153563153564153565153566153567153568153569153570153571153572153573153574153575153576153577153578153579153580153581153582153583153584153585153586153587153588153589153590153591153592153593153594153595153596153597153598153599153600153601153602153603153604153605153606153607153608153609153610153611153612153613153614153615153616153617153618153619153620153621153622153623153624153625153626153627153628153629153630153631153632153633153634153635153636153637153638153639153640153641153642153643153644153645153646153647153648153649153650153651153652153653153654153655153656153657153658153659153660153661153662153663153664153665153666153667153668153669153670153671153672153673153674153675153676153677153678153679153680153681153682153683153684153685153686153687153688153689153690153691153692153693153694153695153696153697153698153699153700153701153702153703153704153705153706153707153708153709153710153711153712153713153714153715153716153717153718153719153720153721153722153723153724153725153726153727153728153729153730153731153732153733153734153735153736153737153738153739153740153741153742153743153744153745153746153747153748153749153750153751153752153753153754153755153756153757153758153759153760153761153762153763153764153765153766153767153768153769153770153771153772153773153774153775153776153777153778153779153780153781153782153783153784153785153786153787153788153789153790153791153792153793153794153795153796153797153798153799153800153801153802153803153804153805153806153807153808153809153810153811153812153813153814153815153816153817153818153819153820153821153822153823153824153825153826153827153828153829153830153831153832153833153834153835153836153837153838153839153840153841153842153843153844153845153846153847153848153849153850153851153852153853153854153855153856153857153858153859153860153861153862153863153864153865153866153867153868153869153870153871153872153873153874153875153876153877153878153879153880153881153882153883153884153885153886153887153888153889153890153891153892153893153894153895153896153897153898153899153900153901153902153903153904153905153906153907153908153909153910153911153912153913153914153915153916153917153918153919153920153921153922153923153924153925153926153927153928153929153930153931153932153933153934153935153936153937153938153939153940153941153942153943153944153945153946153947153948153949153950153951153952153953153954153955153956153957153958153959153960153961153962153963153964153965153966153967153968153969153970153971153972153973153974153975153976153977153978153979153980153981153982153983153984153985153986153987153988153989153990153991153992153993153994153995153996153997153998153999154000154001154002154003154004154005154006154007154008154009154010154011154012154013154014154015154016154017154018154019154020154021154022154023154024154025154026154027154028154029154030154031154032154033154034154035154036154037154038154039154040154041154042154043154044154045154046154047154048154049154050154051154052154053154054154055154056154057154058154059154060154061154062154063154064154065154066154067154068154069154070154071154072154073154074154075154076154077154078154079154080154081154082154083154084154085154086154087154088154089154090154091154092154093154094154095154096154097154098154099154100154101154102154103154104154105154106154107154108154109154110154111154112154113154114154115154116154117154118154119154120154121154122154123154124154125154126154127154128154129154130154131154132154133154134154135154136154137154138154139154140154141154142154143154144154145154146154147154148154149154150154151154152154153154154154155154156154157154158154159154160154161154162154163154164154165154166154167154168154169154170154171154172154173154174154175154176154177154178154179154180154181154182154183154184154185154186154187154188154189154190154191154192154193154194154195154196154197154198154199154200154201154202154203154204154205154206154207154208154209154210154211154212154213154214154215154216154217154218154219154220154221154222154223154224154225154226154227154228154229154230154231154232154233154234154235154236154237154238154239154240154241154242154243154244154245154246154247154248154249154250154251154252154253154254154255154256154257154258154259154260154261154262154263154264154265154266154267154268154269154270154271154272154273154274154275154276154277154278154279154280154281154282154283154284154285154286154287154288154289154290154291154292154293154294154295154296154297154298154299154300154301154302154303154304154305154306154307154308154309154310154311154312154313154314154315154316154317154318154319154320154321154322154323154324154325154326154327154328154329154330154331154332154333154334154335154336154337154338154339154340154341154342154343154344154345154346154347154348154349154350154351154352154353154354154355154356154357154358154359154360154361154362154363154364154365154366154367154368154369154370154371154372154373154374154375154376154377154378154379154380154381154382154383154384154385154386154387154388154389154390154391154392154393154394154395154396154397154398154399154400154401154402154403154404154405154406154407154408154409154410154411154412154413154414154415154416154417154418154419154420154421154422154423154424154425154426154427154428154429154430154431154432154433154434154435154436154437154438154439154440154441154442154443154444154445154446154447154448154449154450154451154452154453154454154455154456154457154458154459154460154461154462154463154464154465154466154467154468154469154470154471154472154473154474154475154476154477154478154479154480154481154482154483154484154485154486154487154488154489154490154491154492154493154494154495154496154497154498154499154500154501154502154503154504154505154506154507154508154509154510154511154512154513154514154515154516154517154518154519154520154521154522154523154524154525154526154527154528154529154530154531154532154533154534154535154536154537154538154539154540154541154542154543154544154545154546154547154548154549154550154551154552154553154554154555154556154557154558154559154560154561154562154563154564154565154566154567154568154569154570154571154572154573154574154575154576154577154578154579154580154581154582154583154584154585154586154587154588154589154590154591154592154593154594154595154596154597154598154599154600154601154602154603154604154605154606154607154608154609154610154611154612154613154614154615154616154617154618154619154620154621154622154623154624154625154626154627154628154629154630154631154632154633154634154635154636154637154638154639154640154641154642154643154644154645154646154647154648154649154650154651154652154653154654154655154656154657154658154659154660154661154662154663154664154665154666154667154668154669154670154671154672154673154674154675154676154677154678154679154680154681154682154683154684154685154686154687154688154689154690154691154692154693154694154695154696154697154698154699154700154701154702154703154704154705154706154707154708154709154710154711154712154713154714154715154716154717154718154719154720154721154722154723154724154725154726154727154728154729154730154731154732154733154734154735154736154737154738154739154740154741154742154743154744154745154746154747154748154749154750154751154752154753154754154755154756154757154758154759154760154761154762154763154764154765154766154767154768154769154770154771154772154773154774154775154776154777154778154779154780154781154782154783154784154785154786154787154788154789154790154791154792154793154794154795154796154797154798154799154800154801154802154803154804154805154806154807154808154809154810154811154812154813154814154815154816154817154818154819154820154821154822154823154824154825154826154827154828154829154830154831154832154833154834154835154836154837154838154839154840154841154842154843154844154845154846154847154848154849154850154851154852154853154854154855154856154857154858154859154860154861154862154863154864154865154866154867154868154869154870154871154872154873154874154875154876154877154878154879154880154881154882154883154884154885154886154887154888154889154890154891154892154893154894154895154896154897154898154899154900154901154902154903154904154905154906154907154908154909154910154911154912154913154914154915154916154917154918154919154920154921154922154923154924154925154926154927154928154929154930154931154932154933154934154935154936154937154938154939154940154941154942154943154944154945154946154947154948154949154950154951154952154953154954154955154956154957154958154959154960154961154962154963154964154965154966154967154968154969154970154971154972154973154974154975154976154977154978154979154980154981154982154983154984154985154986154987154988154989154990154991154992154993154994154995154996154997154998154999155000155001155002155003155004155005155006155007155008155009155010155011155012155013155014155015155016155017155018155019155020155021155022155023155024155025155026155027155028155029155030155031155032155033155034155035155036155037155038155039155040155041155042155043155044155045155046155047155048155049155050155051155052155053155054155055155056155057155058155059155060155061155062155063155064155065155066155067155068155069155070155071155072155073155074155075155076155077155078155079155080155081155082155083155084155085155086155087155088155089155090155091155092155093155094155095155096155097155098155099155100155101155102155103155104155105155106155107155108155109155110155111155112155113155114155115155116155117155118155119155120155121155122155123155124155125155126155127155128155129155130155131155132155133155134155135155136155137155138155139155140155141155142155143155144155145155146155147155148155149155150155151155152155153155154155155155156155157155158155159155160155161155162155163155164155165155166155167155168155169155170155171155172155173155174155175155176155177155178155179155180155181155182155183155184155185155186155187155188155189155190155191155192155193155194155195155196155197155198155199155200155201155202155203155204155205155206155207155208155209155210155211155212155213155214155215155216155217155218155219155220155221155222155223155224155225155226155227155228155229155230155231155232155233155234155235155236155237155238155239155240155241155242155243155244155245155246155247155248155249155250155251155252155253155254155255155256155257155258155259155260155261155262155263155264155265155266155267155268155269155270155271155272155273155274155275155276155277155278155279155280155281155282155283155284155285155286155287155288155289155290155291155292155293155294155295155296155297155298155299155300155301155302155303155304155305155306155307155308155309155310155311155312155313155314155315155316155317155318155319155320155321155322155323155324155325155326155327155328155329155330155331155332155333155334155335155336155337155338155339155340155341155342155343155344155345155346155347155348155349155350155351155352155353155354155355155356155357155358155359155360155361155362155363155364155365155366155367155368155369155370155371155372155373155374155375155376155377155378155379155380155381155382155383155384155385155386155387155388155389155390155391155392155393155394155395155396155397155398155399155400155401155402155403155404155405155406155407155408155409155410155411155412155413155414155415155416155417155418155419155420155421155422155423155424155425155426155427155428155429155430155431155432155433155434155435155436155437155438155439155440155441155442155443155444155445155446155447155448155449155450155451155452155453155454155455155456155457155458155459155460155461155462155463155464155465155466155467155468155469155470155471155472155473155474155475155476155477155478155479155480155481155482155483155484155485155486155487155488155489155490155491155492155493155494155495155496155497155498155499155500155501155502155503155504155505155506155507155508155509155510155511155512155513155514155515155516155517155518155519155520155521155522155523155524155525155526155527155528155529155530155531155532155533155534155535155536155537155538155539155540155541155542155543155544155545155546155547155548155549155550155551155552155553155554155555155556155557155558155559155560155561155562155563155564155565155566155567155568155569155570155571155572155573155574155575155576155577155578155579155580155581155582155583155584155585155586155587155588155589155590155591155592155593155594155595155596155597155598155599155600155601155602155603155604155605155606155607155608155609155610155611155612155613155614155615155616155617155618155619155620155621155622155623155624155625155626155627155628155629155630155631155632155633155634155635155636155637155638155639155640155641155642155643155644155645155646155647155648155649155650155651155652155653155654155655155656155657155658155659155660155661155662155663155664155665155666155667155668155669155670155671155672155673155674155675155676155677155678155679155680155681155682155683155684155685155686155687155688155689155690155691155692155693155694155695155696155697155698155699155700155701155702155703155704155705155706155707155708155709155710155711155712155713155714155715155716155717155718155719155720155721155722155723155724155725155726155727155728155729155730155731155732155733155734155735155736155737155738155739155740155741155742155743155744155745155746155747155748155749155750155751155752155753155754155755155756155757155758155759155760155761155762155763155764155765155766155767155768155769155770155771155772155773155774155775155776155777155778155779155780155781155782155783155784155785155786155787155788155789155790155791155792155793155794155795155796155797155798155799155800155801155802155803155804155805155806155807155808155809155810155811155812155813155814155815155816155817155818155819155820155821155822155823155824155825155826155827155828155829155830155831155832155833155834155835155836155837155838155839155840155841155842155843155844155845155846155847155848155849155850155851155852155853155854155855155856155857155858155859155860155861155862155863155864155865155866155867155868155869155870155871155872155873155874155875155876155877155878155879155880155881155882155883155884155885155886155887155888155889155890155891155892155893155894155895155896155897155898155899155900155901155902155903155904155905155906155907155908155909155910155911155912155913155914155915155916155917155918155919155920155921155922155923155924155925155926155927155928155929155930155931155932155933155934155935155936155937155938155939155940155941155942155943155944155945155946155947155948155949155950155951155952155953155954155955155956155957155958155959155960155961155962155963155964155965155966155967155968155969155970155971155972155973155974155975155976155977155978155979155980155981155982155983155984155985155986155987155988155989155990155991155992155993155994155995155996155997155998155999156000156001156002156003156004156005156006156007156008156009156010156011156012156013156014156015156016156017156018156019156020156021156022156023156024156025156026156027156028156029156030156031156032156033156034156035156036156037156038156039156040156041156042156043156044156045156046156047156048156049156050156051156052156053156054156055156056156057156058156059156060156061156062156063156064156065156066156067156068156069156070156071156072156073156074156075156076156077156078156079156080156081156082156083156084156085156086156087156088156089156090156091156092156093156094156095156096156097156098156099156100156101156102156103156104156105156106156107156108156109156110156111156112156113156114156115156116156117156118156119156120156121156122156123156124156125156126156127156128156129156130156131156132156133156134156135156136156137156138156139156140156141156142156143156144156145156146156147156148156149156150156151156152156153156154156155156156156157156158156159156160156161156162156163156164156165156166156167156168156169156170156171156172156173156174156175156176156177156178156179156180156181156182156183156184156185156186156187156188156189156190156191156192156193156194156195156196156197156198156199156200156201156202156203156204156205156206156207156208156209156210156211156212156213156214156215156216156217156218156219156220156221156222156223156224156225156226156227156228156229156230156231156232156233156234156235156236156237156238156239156240156241156242156243156244156245156246156247156248156249156250156251156252156253156254156255156256156257156258156259156260156261156262156263156264156265156266156267156268156269156270156271156272156273156274156275156276156277156278156279156280156281156282156283156284156285156286156287156288156289156290156291156292156293156294156295156296156297156298156299156300156301156302156303156304156305156306156307156308156309156310156311156312156313156314156315156316156317156318156319156320156321156322156323156324156325156326156327156328156329156330156331156332156333156334156335156336156337156338156339156340156341156342156343156344156345156346156347156348156349156350156351156352156353156354156355156356156357156358156359156360156361156362156363156364156365156366156367156368156369156370156371156372156373156374156375156376156377156378156379156380156381156382156383156384156385156386156387156388156389156390156391156392156393156394156395156396156397156398156399156400156401156402156403156404156405156406156407156408156409156410156411156412156413156414156415156416156417156418156419156420156421156422156423156424156425156426156427156428156429156430156431156432156433156434156435156436156437156438156439156440156441156442156443156444156445156446156447156448156449156450156451156452156453156454156455156456156457156458156459156460156461156462156463156464156465156466156467156468156469156470156471156472156473156474156475156476156477156478156479156480156481156482156483156484156485156486156487156488156489156490156491156492156493156494156495156496156497156498156499156500156501156502156503156504156505156506156507156508156509156510156511156512156513156514156515156516156517156518156519156520156521156522156523156524156525156526156527156528156529156530156531156532156533156534156535156536156537156538156539156540156541156542156543156544156545156546156547156548156549156550156551156552156553156554156555156556156557156558156559156560156561156562156563156564156565156566156567156568156569156570156571156572156573156574156575156576156577156578156579156580156581156582156583156584156585156586156587156588156589156590156591156592156593156594156595156596156597156598156599156600156601156602156603156604156605156606156607156608156609156610156611156612156613156614156615156616156617156618156619156620156621156622156623156624156625156626156627156628156629156630156631156632156633156634156635156636156637156638156639156640156641156642156643156644156645156646156647156648156649156650156651156652156653156654156655156656156657156658156659156660156661156662156663156664156665156666156667156668156669156670156671156672156673156674156675156676156677156678156679156680156681156682156683156684156685156686156687156688156689156690156691156692156693156694156695156696156697156698156699156700156701156702156703156704156705156706156707156708156709156710156711156712156713156714156715156716156717156718156719156720156721156722156723156724156725156726156727156728156729156730156731156732156733156734156735156736156737156738156739156740156741156742156743156744156745156746156747156748156749156750156751156752156753156754156755156756156757156758156759156760156761156762156763156764156765156766156767156768156769156770156771156772156773156774156775156776156777156778156779156780156781156782156783156784156785156786156787156788156789156790156791156792156793156794156795156796156797156798156799156800156801156802156803156804156805156806156807156808156809156810156811156812156813156814156815156816156817156818156819156820156821156822156823156824156825156826156827156828156829156830156831156832156833156834156835156836156837156838156839156840156841156842156843156844156845156846156847156848156849156850156851156852156853156854156855156856156857156858156859156860156861156862156863156864156865156866156867156868156869156870156871156872156873156874156875156876156877156878156879156880156881156882156883156884156885156886156887156888156889156890156891156892156893156894156895156896156897156898156899156900156901156902156903156904156905156906156907156908156909156910156911156912156913156914156915156916156917156918156919156920156921156922156923156924156925156926156927156928156929156930156931156932156933156934156935156936156937156938156939156940156941156942156943156944156945156946156947156948156949156950156951156952156953156954156955156956156957156958156959156960156961156962156963156964156965156966156967156968156969156970156971156972156973156974156975156976156977156978156979156980156981156982156983156984156985156986156987156988156989156990156991156992156993156994156995156996156997156998156999157000157001157002157003157004157005157006157007157008157009157010157011157012157013157014157015157016157017157018157019157020157021157022157023157024157025157026157027157028157029157030157031157032157033157034157035157036157037157038157039157040157041157042157043157044157045157046157047157048157049157050157051157052157053157054157055157056157057157058157059157060157061157062157063157064157065157066157067157068157069157070157071157072157073157074157075157076157077157078157079157080157081157082157083157084157085157086157087157088157089157090157091157092157093157094157095157096157097157098157099157100157101157102157103157104157105157106157107157108157109157110157111157112157113157114157115157116157117157118157119157120157121157122157123157124157125157126157127157128157129157130157131157132157133157134157135157136157137157138157139157140157141157142157143157144157145157146157147157148157149157150157151157152157153157154157155157156157157157158157159157160157161157162157163157164157165157166157167157168157169157170157171157172157173157174157175157176157177157178157179157180157181157182157183157184157185157186157187157188157189157190157191157192157193157194157195157196157197157198157199157200157201157202157203157204157205157206157207157208157209157210157211157212157213157214157215157216157217157218157219157220157221157222157223157224157225157226157227157228157229157230157231157232157233157234157235157236157237157238157239157240157241157242157243157244157245157246157247157248157249157250157251157252157253157254157255157256157257157258157259157260157261157262157263157264157265157266157267157268157269157270157271157272157273157274157275157276157277157278157279157280157281157282157283157284157285157286157287157288157289157290157291157292157293157294157295157296157297157298157299157300157301157302157303157304157305157306157307157308157309157310157311157312157313157314157315157316157317157318157319157320157321157322157323157324157325157326157327157328157329157330157331157332157333157334157335157336157337157338157339157340157341157342157343157344157345157346157347157348157349157350157351157352157353157354157355157356157357157358157359157360157361157362157363157364157365157366157367157368157369157370157371157372157373157374157375157376157377157378157379157380157381157382157383157384157385157386157387157388157389157390157391157392157393157394157395157396157397157398157399157400157401157402157403157404157405157406157407157408157409157410157411157412157413157414157415157416157417157418157419157420157421157422157423157424157425157426157427157428157429157430157431157432157433157434157435157436157437157438157439157440157441157442157443157444157445157446157447157448157449157450157451157452157453157454157455157456157457157458157459157460157461157462157463157464157465157466157467157468157469157470157471157472157473157474157475157476157477157478157479157480157481157482157483157484157485157486157487157488157489157490157491157492157493157494157495157496157497157498157499157500157501157502157503157504157505157506157507157508157509157510157511157512157513157514157515157516157517157518157519157520157521157522157523157524157525157526157527157528157529157530157531157532157533157534157535157536157537157538157539157540157541157542157543157544157545157546157547157548157549157550157551157552157553157554157555157556157557157558157559157560157561157562157563157564157565157566157567157568157569157570157571157572157573157574157575157576157577157578157579157580157581157582157583157584157585157586157587157588157589157590157591157592157593157594157595157596157597157598157599157600157601157602157603157604157605157606157607157608157609157610157611157612157613157614157615157616157617157618157619157620157621157622157623157624157625157626157627157628157629157630157631157632157633157634157635157636157637157638157639157640157641157642157643157644157645157646157647157648157649157650157651157652157653157654157655157656157657157658157659157660157661157662157663157664157665157666157667157668157669157670157671157672157673157674157675157676157677157678157679157680157681157682157683157684157685157686157687157688157689157690157691157692157693157694157695157696157697157698157699157700157701157702157703157704157705157706157707157708157709157710157711157712157713157714157715157716157717157718157719157720157721157722157723157724157725157726157727157728157729157730157731157732157733157734157735157736157737157738157739157740157741157742157743157744157745157746157747157748157749157750157751157752157753157754157755157756157757157758157759157760157761157762157763157764157765157766157767157768157769157770157771157772157773157774157775157776157777157778157779157780157781157782157783157784157785157786157787157788157789157790157791157792157793157794157795157796157797157798157799157800157801157802157803157804157805157806157807157808157809157810157811157812157813157814157815157816157817157818157819157820157821157822157823157824157825157826157827157828157829157830157831157832157833157834157835157836157837157838157839157840157841157842157843157844157845157846157847157848157849157850157851157852157853157854157855157856157857157858157859157860157861157862157863157864157865157866157867157868157869157870157871157872157873157874157875157876157877157878157879157880157881157882157883157884157885157886157887157888157889157890157891157892157893157894157895157896157897157898157899157900157901157902157903157904157905157906157907157908157909157910157911157912157913157914157915157916157917157918157919157920157921157922157923157924157925157926157927157928157929157930157931157932157933157934157935157936157937157938157939157940157941157942157943157944157945157946157947157948157949157950157951157952157953157954157955157956157957157958157959157960157961157962157963157964157965157966157967157968157969157970157971157972157973157974157975157976157977157978157979157980157981157982157983157984157985157986157987157988157989157990157991157992157993157994157995157996157997157998157999158000158001158002158003158004158005158006158007158008158009158010158011158012158013158014158015158016158017158018158019158020158021158022158023158024158025158026158027158028158029158030158031158032158033158034158035158036158037158038158039158040158041158042158043158044158045158046158047158048158049158050158051158052158053158054158055158056158057158058158059158060158061158062158063158064158065158066158067158068158069158070158071158072158073158074158075158076158077158078158079158080158081158082158083158084158085158086158087158088158089158090158091158092158093158094158095158096158097158098158099158100158101158102158103158104158105158106158107158108158109158110158111158112158113158114158115158116158117158118158119158120158121158122158123158124158125158126158127158128158129158130158131158132158133158134158135158136158137158138158139158140158141158142158143158144158145158146158147158148158149158150158151158152158153158154158155158156158157158158158159158160158161158162158163158164158165158166158167158168158169158170158171158172158173158174158175158176158177158178158179158180158181158182158183158184158185158186158187158188158189158190158191158192158193158194158195158196158197158198158199158200158201158202158203158204158205158206158207158208158209158210158211158212158213158214158215158216158217158218158219158220158221158222158223158224158225158226158227158228158229158230158231158232158233158234158235158236158237158238158239158240158241158242158243158244158245158246158247158248158249158250158251158252158253158254158255158256158257158258158259158260158261158262158263158264158265158266158267158268158269158270158271158272158273158274158275158276158277158278158279158280158281158282158283158284158285158286158287158288158289158290158291158292158293158294158295158296158297158298158299158300158301158302158303158304158305158306158307158308158309158310158311158312158313158314158315158316158317158318158319158320158321158322158323158324158325158326158327158328158329158330158331158332158333158334158335158336158337158338158339158340158341158342158343158344158345158346158347158348158349158350158351158352158353158354158355158356158357158358158359158360158361158362158363158364158365158366158367158368158369158370158371158372158373158374158375158376158377158378158379158380158381158382158383158384158385158386158387158388158389158390158391158392158393158394158395158396158397158398158399158400158401158402158403158404158405158406158407158408158409158410158411158412158413158414158415158416158417158418158419158420158421158422158423158424158425158426158427158428158429158430158431158432158433158434158435158436158437158438158439158440158441158442158443158444158445158446158447158448158449158450158451158452158453158454158455158456158457158458158459158460158461158462158463158464158465158466158467158468158469158470158471158472158473158474158475158476158477158478158479158480158481158482158483158484158485158486158487158488158489158490158491158492158493158494158495158496158497158498158499158500158501158502158503158504158505158506158507158508158509158510158511158512158513158514158515158516158517158518158519158520158521158522158523158524158525158526158527158528158529158530158531158532158533158534158535158536158537158538158539158540158541158542158543158544158545158546158547158548158549158550158551158552158553158554158555158556158557158558158559158560158561158562158563158564158565158566158567158568158569158570158571158572158573158574158575158576158577158578158579158580158581158582158583158584158585158586158587158588158589158590158591158592158593158594158595158596158597158598158599158600158601158602158603158604158605158606158607158608158609158610158611158612158613158614158615158616158617158618158619158620158621158622158623158624158625158626158627158628158629158630158631158632158633158634158635158636158637158638158639158640158641158642158643158644158645158646158647158648158649158650158651158652158653158654158655158656158657158658158659158660158661158662158663158664158665158666158667158668158669158670158671158672158673158674158675158676158677158678158679158680158681158682158683158684158685158686158687158688158689158690158691158692158693158694158695158696158697158698158699158700158701158702158703158704158705158706158707158708158709158710158711158712158713158714158715158716158717158718158719158720158721158722158723158724158725158726158727158728158729158730158731158732158733158734158735158736158737158738158739158740158741158742158743158744158745158746158747158748158749158750158751158752158753158754158755158756158757158758158759158760158761158762158763158764158765158766158767158768158769158770158771158772158773158774158775158776158777158778158779158780158781158782158783158784158785158786158787158788158789158790158791158792158793158794158795158796158797158798158799158800158801158802158803158804158805158806158807158808158809158810158811158812158813158814158815158816158817158818158819158820158821158822158823158824158825158826158827158828158829158830158831158832158833158834158835158836158837158838158839158840158841158842158843158844158845158846158847158848158849158850158851158852158853158854158855158856158857158858158859158860158861158862158863158864158865158866158867158868158869158870158871158872158873158874158875158876158877158878158879158880158881158882158883158884158885158886158887158888158889158890158891158892158893158894158895158896158897158898158899158900158901158902158903158904158905158906158907158908158909158910158911158912158913158914158915158916158917158918158919158920158921158922158923158924158925158926158927158928158929158930158931158932158933158934158935158936158937158938158939158940158941158942158943158944158945158946158947158948158949158950158951158952158953158954158955158956158957158958158959158960158961158962158963158964158965158966158967158968158969158970158971158972158973158974158975158976158977158978158979158980158981158982158983158984158985158986158987158988158989158990158991158992158993158994158995158996158997158998158999159000159001159002159003159004159005159006159007159008159009159010159011159012159013159014159015159016159017159018159019159020159021159022159023159024159025159026159027159028159029159030159031159032159033159034159035159036159037159038159039159040159041159042159043159044159045159046159047159048159049159050159051159052159053159054159055159056159057159058159059159060159061159062159063159064159065159066159067159068159069159070159071159072159073159074159075159076159077159078159079159080159081159082159083159084159085159086159087159088159089159090159091159092159093159094159095159096159097159098159099159100159101159102159103159104159105159106159107159108159109159110159111159112159113159114159115159116159117159118159119159120159121159122159123159124159125159126159127159128159129159130159131159132159133159134159135159136159137159138159139159140159141159142159143159144159145159146159147159148159149159150159151159152159153159154159155159156159157159158159159159160159161159162159163159164159165159166159167159168159169159170159171159172159173159174159175159176159177159178159179159180159181159182159183159184159185159186159187159188159189159190159191159192159193159194159195159196159197159198159199159200159201159202159203159204159205159206159207159208159209159210159211159212159213159214159215159216159217159218159219159220159221159222159223159224159225159226159227159228159229159230159231159232159233159234159235159236159237159238159239159240159241159242159243159244159245159246159247159248159249159250159251159252159253159254159255159256159257159258159259159260159261159262159263159264159265159266159267159268159269159270159271159272159273159274159275159276159277159278159279159280159281159282159283159284159285159286159287159288159289159290159291159292159293159294159295159296159297159298159299159300159301159302159303159304159305159306159307159308159309159310159311159312159313159314159315159316159317159318159319159320159321159322159323159324159325159326159327159328159329159330159331159332159333159334159335159336159337159338159339159340159341159342159343159344159345159346159347159348159349159350159351159352159353159354159355159356159357159358159359159360159361159362159363159364159365159366159367159368159369159370159371159372159373159374159375159376159377159378159379159380159381159382159383159384159385159386159387159388159389159390159391159392159393159394159395159396159397159398159399159400159401159402159403159404159405159406159407159408159409159410159411159412159413159414159415159416159417159418159419159420159421159422159423159424159425159426159427159428159429159430159431159432159433159434159435159436159437159438159439159440159441159442159443159444159445159446159447159448159449159450159451159452159453159454159455159456159457159458159459159460159461159462159463159464159465159466159467159468159469159470159471159472159473159474159475159476159477159478159479159480159481159482159483159484159485159486159487159488159489159490159491159492159493159494159495159496159497159498159499159500159501159502159503159504159505159506159507159508159509159510159511159512159513159514159515159516159517159518159519159520159521159522159523159524159525159526159527159528159529159530159531159532159533159534159535159536159537159538159539159540159541159542159543159544159545159546159547159548159549159550159551159552159553159554159555159556159557159558159559159560159561159562159563159564159565159566159567159568159569159570159571159572159573159574159575159576159577159578159579159580159581159582159583159584159585159586159587159588159589159590159591159592159593159594159595159596159597159598159599159600159601159602159603159604159605159606159607159608159609159610159611159612159613159614159615159616159617159618159619159620159621159622159623159624159625159626159627159628159629159630159631159632159633159634159635159636159637159638159639159640159641159642159643159644159645159646159647159648159649159650159651159652159653159654159655159656159657159658159659159660159661159662159663159664159665159666159667159668159669159670159671159672159673159674159675159676159677159678159679159680159681159682159683159684159685159686159687159688159689159690159691159692159693159694159695159696159697159698159699159700159701159702159703159704159705159706159707159708159709159710159711159712159713159714159715159716159717159718159719159720159721159722159723159724159725159726159727159728159729159730159731159732159733159734159735159736159737159738159739159740159741159742159743159744159745159746159747159748159749159750159751159752159753159754159755159756159757159758159759159760159761159762159763159764159765159766159767159768159769159770159771159772159773159774159775159776159777159778159779159780159781159782159783159784159785159786159787159788159789159790159791159792159793159794159795159796159797159798159799159800159801159802159803159804159805159806159807159808159809159810159811159812159813159814159815159816159817159818159819159820159821159822159823159824159825159826159827159828159829159830159831159832159833159834159835159836159837159838159839159840159841159842159843159844159845159846159847159848159849159850159851159852159853159854159855159856159857159858159859159860159861159862159863159864159865159866159867159868159869159870159871159872159873159874159875159876159877159878159879159880159881159882159883159884159885159886159887159888159889159890159891159892159893159894159895159896159897159898159899159900159901159902159903159904159905159906159907159908159909159910159911159912159913159914159915159916159917159918159919159920159921159922159923159924159925159926159927159928159929159930159931159932159933159934159935159936159937159938159939159940159941159942159943159944159945159946159947159948159949159950159951159952159953159954159955159956159957159958159959159960159961159962159963159964159965159966159967159968159969159970159971159972159973159974159975159976159977159978159979159980159981159982159983159984159985159986159987159988159989159990159991159992159993159994159995159996159997159998159999160000160001160002160003160004160005160006160007160008160009160010160011160012160013160014160015160016160017160018160019160020160021160022160023160024160025160026160027160028160029160030160031160032160033160034160035160036160037160038160039160040160041160042160043160044160045160046160047160048160049160050160051160052160053160054160055160056160057160058160059160060160061160062160063160064160065160066160067160068160069160070160071160072160073160074160075160076160077160078160079160080160081160082160083160084160085160086160087160088160089160090160091160092160093160094160095160096160097160098160099160100160101160102160103160104160105160106160107160108160109160110160111160112160113160114160115160116160117160118160119160120160121160122160123160124160125160126160127160128160129160130160131160132160133160134160135160136160137160138160139160140160141160142160143160144160145160146160147160148160149160150160151160152160153160154160155160156160157160158160159160160160161160162160163160164160165160166160167160168160169160170160171160172160173160174160175160176160177160178160179160180160181160182160183160184160185160186160187160188160189160190160191160192160193160194160195160196160197160198160199160200160201160202160203160204160205160206160207160208160209160210160211160212160213160214160215160216160217160218160219160220160221160222160223160224160225160226160227160228160229160230160231160232160233160234160235160236160237160238160239160240160241160242160243160244160245160246160247160248160249160250160251160252160253160254160255160256160257160258160259160260160261160262160263160264160265160266160267160268160269160270160271160272160273160274160275160276160277160278160279160280160281160282160283160284160285160286160287160288160289160290160291160292160293160294160295160296160297160298160299160300160301160302160303160304160305160306160307160308160309160310160311160312160313160314160315160316160317160318160319160320160321160322160323160324160325160326160327160328160329160330160331160332160333160334160335160336160337160338160339160340160341160342160343160344160345160346160347160348160349160350160351160352160353160354160355160356160357160358160359160360160361160362160363160364160365160366160367160368160369160370160371160372160373160374160375160376160377160378160379160380160381160382160383160384160385160386160387160388160389160390160391160392160393160394160395160396160397160398160399160400160401160402160403160404160405160406160407160408160409160410160411160412160413160414160415160416160417160418160419160420160421160422160423160424160425160426160427160428160429160430160431160432160433160434160435160436160437160438160439160440160441160442160443160444160445160446160447160448160449160450160451160452160453160454160455160456160457160458160459160460160461160462160463160464160465160466160467160468160469160470160471160472160473160474160475160476160477160478160479160480160481160482160483160484160485160486160487160488160489160490160491160492160493160494160495160496160497160498160499160500160501160502160503160504160505160506160507160508160509160510160511160512160513160514160515160516160517160518160519160520160521160522160523160524160525160526160527160528160529160530160531160532160533160534160535160536160537160538160539160540160541160542160543160544160545160546160547160548160549160550160551160552160553160554160555160556160557160558160559160560160561160562160563160564160565160566160567160568160569160570160571160572160573160574160575160576160577160578160579160580160581160582160583160584160585160586160587160588160589160590160591160592160593160594160595160596160597160598160599160600160601160602160603160604160605160606160607160608160609160610160611160612160613160614160615160616160617160618160619160620160621160622160623160624160625160626160627160628160629160630160631160632160633160634160635160636160637160638160639160640160641160642160643160644160645160646160647160648160649160650160651160652160653160654160655160656160657160658160659160660160661160662160663160664160665160666160667160668160669160670160671160672160673160674160675160676160677160678160679160680160681160682160683160684160685160686160687160688160689160690160691160692160693160694160695160696160697160698160699160700160701160702160703160704160705160706160707160708160709160710160711160712160713160714160715160716160717160718160719160720160721160722160723160724160725160726160727160728160729160730160731160732160733160734160735160736160737160738160739160740160741160742160743160744160745160746160747160748160749160750160751160752160753160754160755160756160757160758160759160760160761160762160763160764160765160766160767160768160769160770160771160772160773160774160775160776160777160778160779160780160781160782160783160784160785160786160787160788160789160790160791160792160793160794160795160796160797160798160799160800160801160802160803160804160805160806160807160808160809160810160811160812160813160814160815160816160817160818160819160820160821160822160823160824160825160826160827160828160829160830160831160832160833160834160835160836160837160838160839160840160841160842160843160844160845160846160847160848160849160850160851160852160853160854160855160856160857160858160859160860160861160862160863160864160865160866160867160868160869160870160871160872160873160874160875160876160877160878160879160880160881160882160883160884160885160886160887160888160889160890160891160892160893160894160895160896160897160898160899160900160901160902160903160904160905160906160907160908160909160910160911160912160913160914160915160916160917160918160919160920160921160922160923160924160925160926160927160928160929160930160931160932160933160934160935160936160937160938160939160940160941160942160943160944160945160946160947160948160949160950160951160952160953160954160955160956160957160958160959160960160961160962160963160964160965160966160967160968160969160970160971160972160973160974160975160976160977160978160979160980160981160982160983160984160985160986160987160988160989160990160991160992160993160994160995160996160997160998160999161000161001161002161003161004161005161006161007161008161009161010161011161012161013161014161015161016161017161018161019161020161021161022161023161024161025161026161027161028161029161030161031161032161033161034161035161036161037161038161039161040161041161042161043161044161045161046161047161048161049161050161051161052161053161054161055161056161057161058161059161060161061161062161063161064161065161066161067161068161069161070161071161072161073161074161075161076161077161078161079161080161081161082161083161084161085161086161087161088161089161090161091161092161093161094161095161096161097161098161099161100161101161102161103161104161105161106161107161108161109161110161111161112161113161114161115161116161117161118161119161120161121161122161123161124161125161126161127161128161129161130161131161132161133161134161135161136161137161138161139161140161141161142161143161144161145161146161147161148161149161150161151161152161153161154161155161156161157161158161159161160161161161162161163161164161165161166161167161168161169161170161171161172161173161174161175161176161177161178161179161180161181161182161183161184161185161186161187161188161189161190161191161192161193161194161195161196161197161198161199161200161201161202161203161204161205161206161207161208161209161210161211161212161213161214161215161216161217161218161219161220161221161222161223161224161225161226161227161228161229161230161231161232161233161234161235161236161237161238161239161240161241161242161243161244161245161246161247161248161249161250161251161252161253161254161255161256161257161258161259161260161261161262161263161264161265161266161267161268161269161270161271161272161273161274161275161276161277161278161279161280161281161282161283161284161285161286161287161288161289161290161291161292161293161294161295161296161297161298161299161300161301161302161303161304161305161306161307161308161309161310161311161312161313161314161315161316161317161318161319161320161321161322161323161324161325161326161327161328161329161330161331161332161333161334161335161336161337161338161339161340161341161342161343161344161345161346161347161348161349161350161351161352161353161354161355161356161357161358161359161360161361161362161363161364161365161366161367161368161369161370161371161372161373161374161375161376161377161378161379161380161381161382161383161384161385161386161387161388161389161390161391161392161393161394161395161396161397161398161399161400161401161402161403161404161405161406161407161408161409161410161411161412161413161414161415161416161417161418161419161420161421161422161423161424161425161426161427161428161429161430161431161432161433161434161435161436161437161438161439161440161441161442161443161444161445161446161447161448161449161450161451161452161453161454161455161456161457161458161459161460161461161462161463161464161465161466161467161468161469161470161471161472161473161474161475161476161477161478161479161480161481161482161483161484161485161486161487161488161489161490161491161492161493161494161495161496161497161498161499161500161501161502161503161504161505161506161507161508161509161510161511161512161513161514161515161516161517161518161519161520161521161522161523161524161525161526161527161528161529161530161531161532161533161534161535161536161537161538161539161540161541161542161543161544161545161546161547161548161549161550161551161552161553161554161555161556161557161558161559161560161561161562161563161564161565161566161567161568161569161570161571161572161573161574161575161576161577161578161579161580161581161582161583161584161585161586161587161588161589161590161591161592161593161594161595161596161597161598161599161600161601161602161603161604161605161606161607161608161609161610161611161612161613161614161615161616161617161618161619161620161621161622161623161624161625161626161627161628161629161630161631161632161633161634161635161636161637161638161639161640161641161642161643161644161645161646161647161648161649161650161651161652161653161654161655161656161657161658161659161660161661161662161663161664161665161666161667161668161669161670161671161672161673161674161675161676161677161678161679161680161681161682161683161684161685161686161687161688161689161690161691161692161693161694161695161696161697161698161699161700161701161702161703161704161705161706161707161708161709161710161711161712161713161714161715161716161717161718161719161720161721161722161723161724161725161726161727161728161729161730161731161732161733161734161735161736161737161738161739161740161741161742161743161744161745161746161747161748161749161750161751161752161753161754161755161756161757161758161759161760161761161762161763161764161765161766161767161768161769161770161771161772161773161774161775161776161777161778161779161780161781161782161783161784161785161786161787161788161789161790161791161792161793161794161795161796161797161798161799161800161801161802161803161804161805161806161807161808161809161810161811161812161813161814161815161816161817161818161819161820161821161822161823161824161825161826161827161828161829161830161831161832161833161834161835161836161837161838161839161840161841161842161843161844161845161846161847161848161849161850161851161852161853161854161855161856161857161858161859161860161861161862161863161864161865161866161867161868161869161870161871161872161873161874161875161876161877161878161879161880161881161882161883161884161885161886161887161888161889161890161891161892161893161894161895161896161897161898161899161900161901161902161903161904161905161906161907161908161909161910161911161912161913161914161915161916161917161918161919161920161921161922161923161924161925161926161927161928161929161930161931161932161933161934161935161936161937161938161939161940161941161942161943161944161945161946161947161948161949161950161951161952161953161954161955161956161957161958161959161960161961161962161963161964161965161966161967161968161969161970161971161972161973161974161975161976161977161978161979161980161981161982161983161984161985161986161987161988161989161990161991161992161993161994161995161996161997161998161999162000162001162002162003162004162005162006162007162008162009162010162011162012162013162014162015162016162017162018162019162020162021162022162023162024162025162026162027162028162029162030162031162032162033162034162035162036162037162038162039162040162041162042162043162044162045162046162047162048162049162050162051162052162053162054162055162056162057162058162059162060162061162062162063162064162065162066162067162068162069162070162071162072162073162074162075162076162077162078162079162080162081162082162083162084162085162086162087162088162089162090162091162092162093162094162095162096162097162098162099162100162101162102162103162104162105162106162107162108162109162110162111162112162113162114162115162116162117162118162119162120162121162122162123162124162125162126162127162128162129162130162131162132162133162134162135162136162137162138162139162140162141162142162143162144162145162146162147162148162149162150162151162152162153162154162155162156162157162158162159162160162161162162162163162164162165162166162167162168162169162170162171162172162173162174162175162176162177162178162179162180162181162182162183162184162185162186162187162188162189162190162191162192162193162194162195162196162197162198162199162200162201162202162203162204162205162206162207162208162209162210162211162212162213162214162215162216162217162218162219162220162221162222162223162224162225162226162227162228162229162230162231162232162233162234162235162236162237162238162239162240162241162242162243162244162245162246162247162248162249162250162251162252162253162254162255162256162257162258162259162260162261162262162263162264162265162266162267162268162269162270162271162272162273162274162275162276162277162278162279162280162281162282162283162284162285162286162287162288162289162290162291162292162293162294162295162296162297162298162299162300162301162302162303162304162305162306162307162308162309162310162311162312162313162314162315162316162317162318162319162320162321162322162323162324162325162326162327162328162329162330162331162332162333162334162335162336162337162338162339162340162341162342162343162344162345162346162347162348162349162350162351162352162353162354162355162356162357162358162359162360162361162362162363162364162365162366162367162368162369162370162371162372162373162374162375162376162377162378162379162380162381162382162383162384162385162386162387162388162389162390162391162392162393162394162395162396162397162398162399162400162401162402162403162404162405162406162407162408162409162410162411162412162413162414162415162416162417162418162419162420162421162422162423162424162425162426162427162428162429162430162431162432162433162434162435162436162437162438162439162440162441162442162443162444162445162446162447162448162449162450162451162452162453162454162455162456162457162458162459162460162461162462162463162464162465162466162467162468162469162470162471162472162473162474162475162476162477162478162479162480162481162482162483162484162485162486162487162488162489162490162491162492162493162494162495162496162497162498162499162500162501162502162503162504162505162506162507162508162509162510162511162512162513162514162515162516162517162518162519162520162521162522162523162524162525162526162527162528162529162530162531162532162533162534162535162536162537162538162539162540162541162542162543162544162545162546162547162548162549162550162551162552162553162554162555162556162557162558162559162560162561162562162563162564162565162566162567162568162569162570162571162572162573162574162575162576162577162578162579162580162581162582162583162584162585162586162587162588162589162590162591162592162593162594162595162596162597162598162599162600162601162602162603162604162605162606162607162608162609162610162611162612162613162614162615162616162617162618162619162620162621162622162623162624162625162626162627162628162629162630162631162632162633162634162635162636162637162638162639162640162641162642162643162644162645162646162647162648162649162650162651162652162653162654162655162656162657162658162659162660162661162662162663162664162665162666162667162668162669162670162671162672162673162674162675162676162677162678162679162680162681162682162683162684162685162686162687162688162689162690162691162692162693162694162695162696162697162698162699162700162701162702162703162704162705162706162707162708162709162710162711162712162713162714162715162716162717162718162719162720162721162722162723162724162725162726162727162728162729162730162731162732162733162734162735162736162737162738162739162740162741162742162743162744162745162746162747162748162749162750162751162752162753162754162755162756162757162758162759162760162761162762162763162764162765162766162767162768162769162770162771162772162773162774162775162776162777162778162779162780162781162782162783162784162785162786162787162788162789162790162791162792162793162794162795162796162797162798162799162800162801162802162803162804162805162806162807162808162809162810162811162812162813162814162815162816162817162818162819162820162821162822162823162824162825162826162827162828162829162830162831162832162833162834162835162836162837162838162839162840162841162842162843162844162845162846162847162848162849162850162851162852162853162854162855162856162857162858162859162860162861162862162863162864162865162866162867162868162869162870162871162872162873162874162875162876162877162878162879162880162881162882162883162884162885162886162887162888162889162890162891162892162893162894162895162896162897162898162899162900162901162902162903162904162905162906162907162908162909162910162911162912162913162914162915162916162917162918162919162920162921162922162923162924162925162926162927162928162929162930162931162932162933162934162935162936162937162938162939162940162941162942162943162944162945162946162947162948162949162950162951162952162953162954162955162956162957162958162959162960162961162962162963162964162965162966162967162968162969162970162971162972162973162974162975162976162977162978162979162980162981162982162983162984162985162986162987162988
  1. #!/usr/bin/env php
  2. <?php
  3. declare(strict_types=1);
  4. /*
  5. * This file is part of PHP CS Fixer.
  6. *
  7. * (c) Fabien Potencier <fabien@symfony.com>
  8. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  9. *
  10. * This source file is subject to the MIT license that is bundled
  11. * with this source code in the file LICENSE.
  12. */
  13. use Composer\XdebugHandler\XdebugHandler;
  14. use PhpCsFixer\Console\Application;
  15. error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
  16. set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
  17. if (0 !== ($severity & error_reporting())) {
  18. throw new ErrorException($message, 0, $severity, $file, $line);
  19. }
  20. return true;
  21. });
  22. // check environment requirements
  23. (static function (): void {
  24. if (\PHP_VERSION_ID === (int) '80000') { // TODO use 8_00_00 once only PHP 7.4+ is supported by this entry file
  25. fwrite(STDERR, "PHP CS Fixer is not able run on PHP 8.0.0 due to bug in PHP tokenizer (https://bugs.php.net/bug.php?id=80462).\n");
  26. fwrite(STDERR, "Update PHP version to unblock execution.\n");
  27. exit(1);
  28. }
  29. if (\PHP_VERSION_ID < (int) '70400') {
  30. fwrite(STDERR, "PHP needs to be a minimum version of PHP 7.4.0.\n");
  31. fwrite(STDERR, 'Current PHP version: '.PHP_VERSION.".\n");
  32. exit(1);
  33. }
  34. // @TODO 4.0 cleanup
  35. if (false !== getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  36. fwrite(STDERR, "Setting PHP_CS_FIXER_IGNORE_ENV environment variable is deprecated and will be removed in 4.0, use unsupportedPhpVersionAllowed config instead.\n");
  37. }
  38. foreach (['json', 'tokenizer'] as $extension) {
  39. if (!extension_loaded($extension)) {
  40. fwrite(STDERR, sprintf("PHP extension ext-%s is missing from your system. Install or enable it.\n", $extension));
  41. if (filter_var(getenv('PHP_CS_FIXER_IGNORE_ENV'), FILTER_VALIDATE_BOOLEAN)) {
  42. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  43. } else {
  44. exit(1);
  45. }
  46. }
  47. }
  48. })();
  49. // load dependencies
  50. (static function (): void {
  51. $require = true;
  52. if (class_exists('Phar')) {
  53. // Maybe this file is used as phar-stub? Let's try!
  54. try {
  55. Phar::mapPhar('php-cs-fixer.phar');
  56. /** @phpstan-ignore requireOnce.fileNotFound */
  57. require_once 'phar://php-cs-fixer.phar/vendor/autoload.php';
  58. $require = false;
  59. } catch (PharException $e) {
  60. }
  61. }
  62. if ($require) {
  63. // OK, it's not, let give Composer autoloader a try!
  64. $possibleFiles = [__DIR__.'/../../autoload.php', __DIR__.'/../autoload.php', __DIR__.'/vendor/autoload.php'];
  65. $file = null;
  66. foreach ($possibleFiles as $possibleFile) {
  67. if (file_exists($possibleFile)) {
  68. $file = $possibleFile;
  69. break;
  70. }
  71. }
  72. if (null === $file) {
  73. throw new RuntimeException('Unable to locate autoload.php file.');
  74. }
  75. require_once $file;
  76. }
  77. })();
  78. // Restart if xdebug is loaded, unless the environment variable PHP_CS_FIXER_ALLOW_XDEBUG is set.
  79. $xdebug = new XdebugHandler('PHP_CS_FIXER');
  80. $xdebug->check();
  81. unset($xdebug);
  82. $application = new Application();
  83. $application->run();
  84. __HALT_COMPILER(); ?>
  85. ,�÷�������������� ���php-cs-fixer- ��è‰mh- ��¹öÚ[¤���������LICENSE8��è‰mh8��@€¤���������ci-integration.sh½��è‰mh½��²¬k+¤������-���vendor/fidry/cpu-core-counter/bin/execute.php3��è‰mh3��nmC0¤������+���vendor/fidry/cpu-core-counter/bin/trace.phpè��è‰mhè��VQS¤������.���vendor/fidry/cpu-core-counter/bin/diagnose.php>��è‰mh>��±Ût¯¤������4���vendor/fidry/cpu-core-counter/src/CpuCoreCounter.php{��è‰mh{��ÝÙV±¤������/���vendor/fidry/cpu-core-counter/src/Diagnoser.phpÌ��è‰mhÌ��ý4v²¤������;���vendor/fidry/cpu-core-counter/src/ParallelisationResult.php
  86. ��è‰mh
  87. ��J S¤������=���vendor/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php��è‰mh��Í̄Ĥ������@���vendor/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.phpA��è‰mhA��­c…÷¤������C���vendor/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.phpê��è‰mhê��É„ƒ5¤������>���vendor/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.phpœ��è‰mhœ��¼û/h¤������?���vendor/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.phpÿ��è‰mhÿ��¸¯@Û¤������:���vendor/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.phpä���è‰mhä���„K¤������8���vendor/fidry/cpu-core-counter/src/Finder/NProcFinder.phpH��è‰mhH��·² «¤������I���vendor/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php¬��è‰mh¬��—Èû¤������?���vendor/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.php‡��è‰mh‡��
  88. œj¤������<���vendor/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.php$��è‰mh$��=О¤������=���vendor/fidry/cpu-core-counter/src/Finder/NProcessorFinder.php&��è‰mh&��•Ф������;���vendor/fidry/cpu-core-counter/src/Finder/FinderRegistry.php��è‰mh��,ºÈä������=���vendor/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php'��è‰mh'��¿Ý—Ô¤������>���vendor/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.php)��è‰mh)��Ò–`¤������A���vendor/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.phpR��è‰mhR��¡"*¯¤������C���vendor/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.php^��è‰mh^��~r6¤������@���vendor/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.phpç��è‰mhç��%ež¤������D���vendor/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.phpÐ��è‰mhÐ��Ä L¤������>���vendor/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.php ��è‰mh ��Šlbؤ������A���vendor/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.phpU��è‰mhU��c{s ¤������?���vendor/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.php†��è‰mh†��uLr¤������>���vendor/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.phpH��è‰mhH��‚I\L¤������:���vendor/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.phpc��è‰mhc��W&Èm¤������>���vendor/fidry/cpu-core-counter/src/Executor/ProcessExecutor.php§���è‰mh§���`8ýÓ¤������?���vendor/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.phpç��è‰mhç��ɧç|¤������(���vendor/clue/ndjson-react/src/Encoder.phpä ��è‰mhä ��É×¶ ¤������(���vendor/clue/ndjson-react/src/Decoder.phpÎ ��è‰mhÎ ��¼ˆö¤���������vendor/autoload.phpv��è‰mhv��oB¤������'���vendor/composer/autoload_namespaces.phpZ���è‰mhZ���ë¦á–¤������0���vendor/composer/xdebug-handler/src/PhpConfig.php¯��è‰mh¯��K€D{¤������-���vendor/composer/xdebug-handler/src/Status.phpÒ ��è‰mhÒ ��±Ít¤������4���vendor/composer/xdebug-handler/src/XdebugHandler.php'-��è‰mh'-��5§ÿ¤������.���vendor/composer/xdebug-handler/src/Process.phpò��è‰mhò��fžZ.¤���������vendor/composer/ClassLoader.php/��è‰mh/��˜Õâ’¤������!���vendor/composer/autoload_psr4.phpL
  89. ��è‰mhL
  90. ��Ù%�¤������%���vendor/composer/autoload_classmap.phpä¼�è‰mhä¼�Çÿ¤������"���vendor/composer/platform_check.php ��è‰mh ��‚/¶i¤������#���vendor/composer/autoload_static.php^ò�è‰mh^ò�½‚k²¤������!���vendor/composer/autoload_real.php"��è‰mh"��䌬®¤������/���vendor/composer/semver/src/CompilingMatcher.php©��è‰mh©��9`½™¤������'���vendor/composer/semver/src/Interval.phpæ��è‰mhæ��=[i¤������)���vendor/composer/semver/src/Comparator.php#��è‰mh#��*A”ƒ¤������(���vendor/composer/semver/src/Intervals.php,��è‰mh,��"ŠTú¤������%���vendor/composer/semver/src/Semver.phpù��è‰mhù��á-i¤������,���vendor/composer/semver/src/VersionParser.php&.��è‰mh&.��
  91. ³X¤������=���vendor/composer/semver/src/Constraint/ConstraintInterface.php´��è‰mh´��"ƒ¼E¤������9���vendor/composer/semver/src/Constraint/MultiConstraint.php¯��è‰mh¯��ïÍx¤������4���vendor/composer/semver/src/Constraint/Constraint.php›��è‰mh›��Ú3lФ������<���vendor/composer/semver/src/Constraint/MatchAllConstraint.php¯��è‰mh¯��²Eú¤������=���vendor/composer/semver/src/Constraint/MatchNoneConstraint.phpÉ��è‰mhÉ��֯خ¤������/���vendor/composer/semver/src/Constraint/Bound.phpw��è‰mhw��W4]W¤������"���vendor/composer/autoload_files.php��è‰mh��õa¤������%���vendor/composer/InstalledVersions.php‚��è‰mh‚��à™ª¤���������vendor/composer/installed.php)��è‰mh)��7Š-¤������E���vendor/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php× ��è‰mh× ��ñ@í¤������L���vendor/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php ��è‰mh �� .GW¤������G���vendor/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php1��è‰mh1��Â}ÌÒ¤������<���vendor/composer/pcre/src/PHPStan/InvalidRegexPatternRule.phpò ��è‰mhò ��{jΤ������3���vendor/composer/pcre/src/PHPStan/PregMatchFlags.phpü��è‰mhü��û üÀ¤������?���vendor/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php{
  92. ��è‰mh{
  93. �� UU¤������(���vendor/composer/pcre/src/MatchResult.php ��è‰mh �� ;�Ф������"���vendor/composer/pcre/src/Regex.php2��è‰mh2��ÑQ¤������6���vendor/composer/pcre/src/MatchAllWithOffsetsResult.phps��è‰mhs��e�¨¤������3���vendor/composer/pcre/src/MatchWithOffsetsResult.php7��è‰mh7��B�Oè¤������7���vendor/composer/pcre/src/MatchAllStrictGroupsResult.phpS��è‰mhS��Ó ø¡¤������9���vendor/composer/pcre/src/UnexpectedNullMatchException.php��è‰mh�� îÀò¤������4���vendor/composer/pcre/src/MatchStrictGroupsResult.php��è‰mh��32詤������+���vendor/composer/pcre/src/MatchAllResult.phpG��è‰mhG��uÜ}¤������*���vendor/composer/pcre/src/ReplaceResult.php@��è‰mh@��òÚÛ4¤������!���vendor/composer/pcre/src/Preg.phpÍ!��è‰mhÍ!��´rÏb¤������*���vendor/composer/pcre/src/PcreException.php��è‰mh��´ Ƥ������=���vendor/psr/event-dispatcher/src/ListenerProviderInterface.php²���è‰mh²���7
  94. ¤������<���vendor/psr/event-dispatcher/src/EventDispatcherInterface.phpœ���è‰mhœ���ÑISؤ������;���vendor/psr/event-dispatcher/src/StoppableEventInterface.php¦���è‰mh¦����Ç.¤������7���vendor/psr/container/src/NotFoundExceptionInterface.phpq���è‰mhq���Rúõ¤������/���vendor/psr/container/src/ContainerInterface.php·���è‰mh·���Šã¼¤������8���vendor/psr/container/src/ContainerExceptionInterface.phpp���è‰mhp���;ZÃ
  95. ¤������/���vendor/psr/log/Psr/Log/LoggerAwareInterface.php|���è‰mh|���$£ˆ¤������#���vendor/psr/log/Psr/Log/LogLevel.phpû���è‰mhû���jðñ8¤������+���vendor/psr/log/Psr/Log/LoggerAwareTrait.php§���è‰mh§���T½úB¤������3���vendor/psr/log/Psr/Log/InvalidArgumentException.php`���è‰mh`��� ˆX1¤������%���vendor/psr/log/Psr/Log/NullLogger.phpŸ���è‰mhŸ����Xóª¤������*���vendor/psr/log/Psr/Log/LoggerInterface.phpÈ��è‰mhÈ��šx¤������&���vendor/psr/log/Psr/Log/LoggerTrait.phpk��è‰mhk��£}‰’¤������)���vendor/psr/log/Psr/Log/AbstractLogger.php;��è‰mh;��ñ>3[¤������'���vendor/symfony/polyfill-php73/Php73.phpn��è‰mhn��Cs¥l¤������?���vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php[���è‰mh[���M²Ü¤������+���vendor/symfony/polyfill-php73/bootstrap.phpù��è‰mhù��AY8Ƥ������*���vendor/symfony/polyfill-php80/PhpToken.php��è‰mh��x‚Àˤ������:���vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php����è‰mh����Ú”ݤ������<���vendor/symfony/polyfill-php80/Resources/stubs/ValueError.phpT���è‰mhT���‘Öw—¤������;���vendor/symfony/polyfill-php80/Resources/stubs/Attribute.phpÇ��è‰mhÇ��ÝÞíû¤������E���vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php]���è‰mh]���ºgä������<���vendor/symfony/polyfill-php80/Resources/stubs/Stringable.phpk���è‰mhk���Ðý+¤������+���vendor/symfony/polyfill-php80/bootstrap.phpú��è‰mhú��×îå¤������'���vendor/symfony/polyfill-php80/Php80.php¡ ��è‰mh¡ ��[Âk ¤������-���vendor/symfony/polyfill-ctype/bootstrap80.phph��è‰mhh��K¿y¸¤������+���vendor/symfony/polyfill-ctype/bootstrap.php2��è‰mh2��Èa­8¤������'���vendor/symfony/polyfill-ctype/Ctype.php‡
  96. ��è‰mh‡
  97. ��~¶d¸¤������F���vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.phpŸ���è‰mhŸ���ÎÀ¾ü¤������@���vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php‚��è‰mh‚��áÁ?ì¤������+���vendor/symfony/polyfill-php81/bootstrap.phpô��è‰mhô��ˆÓÐ\¤������'���vendor/symfony/polyfill-php81/Php81.php;��è‰mh;��ù«d¤������<���vendor/symfony/event-dispatcher/EventDispatcherInterface.php ��è‰mh ��±�xV¤������=���vendor/symfony/event-dispatcher/Attribute/AsEventListener.phpd��è‰mhd��Àú®ƒ¤������>���vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.phpÈ��è‰mhÈ��‘§b¤������3���vendor/symfony/event-dispatcher/EventDispatcher.php>��è‰mh>��!‚÷¡¤������<���vendor/symfony/event-dispatcher/EventSubscriberInterface.php³���è‰mh³���!jcK¤������<���vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php«��è‰mh«��Q¹:-¤������0���vendor/symfony/event-dispatcher/GenericEvent.phpG��è‰mhG��à.Y¤������M���vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.phpÌ��è‰mhÌ��‡E\‡¤������K���vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.phpß��è‰mhß��'"”L¤������B���vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php‚��è‰mh‚��(�¤������9���vendor/symfony/event-dispatcher/Debug/WrappedListener.php3 ��è‰mh3 ��Év]K¤������(���vendor/symfony/filesystem/Filesystem.php$B��è‰mh$B��’Àw;¤������"���vendor/symfony/filesystem/Path.phpb'��è‰mhb'��ߣ¤������<���vendor/symfony/filesystem/Exception/IOExceptionInterface.php¦���è‰mh¦���jÙwM¤������:���vendor/symfony/filesystem/Exception/ExceptionInterface.php|���è‰mh|����éD¤������8���vendor/symfony/filesystem/Exception/RuntimeException.php™���è‰mh™���ÝUUH¤������3���vendor/symfony/filesystem/Exception/IOException.php›��è‰mh›��3_Ãê¤������@���vendor/symfony/filesystem/Exception/InvalidArgumentException.php©���è‰mh©����!Ǥ������=���vendor/symfony/filesystem/Exception/FileNotFoundException.phpÑ��è‰mhÑ��bæ}´¤������6���vendor/symfony/options-resolver/OptionConfigurator.php…��è‰mh…��z¤g�¤������3���vendor/symfony/options-resolver/OptionsResolver.php%W��è‰mh%W��)îæy¤������+���vendor/symfony/options-resolver/Options.php{���è‰mh{���é|·Š¤������E���vendor/symfony/options-resolver/Exception/InvalidOptionsException.php’���è‰mh’���ëÿk ¤������E���vendor/symfony/options-resolver/Exception/MissingOptionsException.php’���è‰mh’���=¼½�¤������=���vendor/symfony/options-resolver/Exception/AccessException.phpž���è‰mhž���›5¤������G���vendor/symfony/options-resolver/Exception/OptionDefinitionException.php§���è‰mh§���ó@4�¤������@���vendor/symfony/options-resolver/Exception/ExceptionInterface.php����è‰mh����Œ°É&¤������F���vendor/symfony/options-resolver/Exception/InvalidArgumentException.php°���è‰mh°���²G¹¤������C���vendor/symfony/options-resolver/Exception/NoSuchOptionException.php®���è‰mh®���g]ÝȤ������F���vendor/symfony/options-resolver/Exception/NoConfigurationException.phpõ���è‰mhõ���j‘®E¤������G���vendor/symfony/options-resolver/Exception/UndefinedOptionsException.php•���è‰mh•���p Í�¤������E���vendor/symfony/options-resolver/Debug/OptionsResolverIntrospector.php€��è‰mh€��Ì$-0¤������7���vendor/symfony/polyfill-intl-normalizer/bootstrap80.phpé��è‰mhé��=år´¤������6���vendor/symfony/polyfill-intl-normalizer/Normalizer.phpö��è‰mhö��êiÝe¤������F���vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php.��è‰mh.��Qs$—¤������L���vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.phpt.��è‰mht.�� q�ܤ������T���vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.phpaˆ��è‰mhaˆ��çR½}¤������R���vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php‰=��è‰mh‰=��*ïo?¤������X���vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php™è��è‰mh™è��o”e)¤������5���vendor/symfony/polyfill-intl-normalizer/bootstrap.phpë��è‰mhë��Pú£D¤������F���vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php3��è‰mh3���ºn¤������3���vendor/symfony/event-dispatcher-contracts/Event.php„��è‰mh„��›»Ö°¤������%���vendor/symfony/finder/SplFileInfo.php½��è‰mh½��y¤������5���vendor/symfony/finder/Comparator/NumberComparator.phpz��è‰mhz��+¼�h¤������/���vendor/symfony/finder/Comparator/Comparator.php4��è‰mh4��"ì¼Õ¤������3���vendor/symfony/finder/Comparator/DateComparator.php��è‰mh��Ï%úe¤������ ���vendor/symfony/finder/Finder.phpæ'��è‰mhæ'��¹ 1Ф���������vendor/symfony/finder/Glob.phpÇ��è‰mhÇ��Db‡³¤������/���vendor/symfony/finder/Iterator/LazyIterator.phpQ��è‰mhQ��n]¿¼¤������;���vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.phpw
  98. ��è‰mhw
  99. ��ŵ3¤������<���vendor/symfony/finder/Iterator/FilecontentFilterIterator.phpd��è‰mhd��™0ç"¤������=���vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.phpÀ��è‰mhÀ��0š¥¤������:���vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php‰��è‰mh‰��(jº¤������9���vendor/symfony/finder/Iterator/FilenameFilterIterator.php¡��è‰mh¡��Ò®Áô¤������:���vendor/symfony/finder/Iterator/DateRangeFilterIterator.phpœ��è‰mhœ��q†ãX¤������7���vendor/symfony/finder/Iterator/CustomFilterIterator.phpp��è‰mhp��.EÚþ¤������=���vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.phpK ��è‰mhK ��é†F ¤������A���vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.phpH��è‰mhH�� [”c¤������3���vendor/symfony/finder/Iterator/SortableIterator.php8
  100. ��è‰mh8
  101. ��äQYf¤������;���vendor/symfony/finder/Iterator/DepthRangeFilterIterator.phpJ��è‰mhJ��õ­s<¤������9���vendor/symfony/finder/Iterator/FileTypeFilterIterator.php•��è‰mh•��< Hu¤������5���vendor/symfony/finder/Iterator/PathFilterIterator.phpÿ��è‰mhÿ��Y\�d¤������#���vendor/symfony/finder/Gitignore.php³��è‰mh³��s 4¤������9���vendor/symfony/finder/Exception/AccessDeniedException.php„���è‰mh„���½¾sœ¤������>���vendor/symfony/finder/Exception/DirectoryNotFoundException.php‰���è‰mh‰���a)ÿ¤������&���vendor/symfony/stopwatch/Stopwatch.php ��è‰mh ��3¶%¨¤������$���vendor/symfony/stopwatch/Section.phpê��è‰mhê��‡g±±¤������,���vendor/symfony/stopwatch/StopwatchPeriod.phpû��è‰mhû��òѳH¤������+���vendor/symfony/stopwatch/StopwatchEvent.php
  102. ��è‰mh
  103. ��JvǤ������)���vendor/symfony/string/CodePointString.phpõ��è‰mhõ��BÂ�¤������(���vendor/symfony/string/AbstractString.php*4��è‰mh*4��°J û¤������-���vendor/symfony/string/Resources/functions.php��è‰mh��cÚª"¤������<���vendor/symfony/string/Resources/data/wcswidth_table_zero.phpÔ��è‰mhÔ��Òþ$¤������<���vendor/symfony/string/Resources/data/wcswidth_table_wide.php$��è‰mh$��¥À–K¤������3���vendor/symfony/string/Inflector/FrenchInflector.phpˆ
  104. ��è‰mhˆ
  105. ��·ŠH¤������6���vendor/symfony/string/Inflector/InflectorInterface.php×���è‰mh×���hD£¤������4���vendor/symfony/string/Inflector/EnglishInflector.phpJ��è‰mhJ��³Ø3¤������/���vendor/symfony/string/AbstractUnicodeString.php¸R��è‰mh¸R��#·¤������$���vendor/symfony/string/LazyString.phpC ��è‰mhC ��§á¬b¤������$���vendor/symfony/string/ByteString.phpÿ+��è‰mhÿ+��K«Ó^¤������'���vendor/symfony/string/UnicodeString.phpí%��è‰mhí%��ýÁ˜5¤������6���vendor/symfony/string/Exception/ExceptionInterface.phps���è‰mhs���qHV‘¤������4���vendor/symfony/string/Exception/RuntimeException.php’���è‰mh’���u‘g¤������<���vendor/symfony/string/Exception/InvalidArgumentException.php¢���è‰mh¢���¥A¤������2���vendor/symfony/string/Slugger/SluggerInterface.php��è‰mh���kñ¨¤������.���vendor/symfony/string/Slugger/AsciiSlugger.phpì��è‰mhì��}&ʤ������1���vendor/symfony/deprecation-contracts/function.php=��è‰mh=��žÁ´ ¤������?���vendor/symfony/service-contracts/ServiceSubscriberInterface.php³���è‰mh³���—öd ¤������@���vendor/symfony/service-contracts/Attribute/SubscribedService.php
  106. ��è‰mh
  107. ��1I®T¤������7���vendor/symfony/service-contracts/Attribute/Required.php¨���è‰mh¨���xj네������3���vendor/symfony/service-contracts/ResetInterface.phpy���è‰mhy���°·jå¤������=���vendor/symfony/service-contracts/ServiceProviderInterface.phpÞ���è‰mhÞ���úRèk¤������;���vendor/symfony/service-contracts/ServiceSubscriberTrait.php`
  108. ��è‰mh`
  109. ��È3u¤������8���vendor/symfony/service-contracts/ServiceLocatorTrait.phpã ��è‰mhã ��"�5é¤������+���vendor/symfony/process/ExecutableFinder.phpø��è‰mhø��¿[ª¤������*���vendor/symfony/process/Pipes/UnixPipes.php€��è‰mh€��¾”Vv¤������-���vendor/symfony/process/Pipes/WindowsPipes.php4 ��è‰mh4 �� VÄà¤������.���vendor/symfony/process/Pipes/AbstractPipes.php ��è‰mh ��kSQ¤������/���vendor/symfony/process/Pipes/PipesInterface.php™��è‰mh™��fQÚ ¤������&���vendor/symfony/process/InputStream.php@��è‰mh@��•˱¤������%���vendor/symfony/process/PhpProcess.phpø��è‰mhø��pÄX¤������.���vendor/symfony/process/PhpExecutableFinder.phpÿ��è‰mhÿ��ê®ÅŒ¤������=���vendor/symfony/process/Exception/ProcessSignaledException.php��è‰mh��Yשâ¤������3���vendor/symfony/process/Exception/LogicException.php”���è‰mh”��� ³ãñ¤������7���vendor/symfony/process/Exception/ExceptionInterface.phpy���è‰mhy���qVXJ¤������;���vendor/symfony/process/Exception/ProcessFailedException.phpx��è‰mhx��¨Ìzy¤������5���vendor/symfony/process/Exception/RuntimeException.php˜���è‰mh˜���¢Ø:¤������=���vendor/symfony/process/Exception/ProcessTimedOutException.php1��è‰mh1��‚'Z¤������=���vendor/symfony/process/Exception/InvalidArgumentException.php¨���è‰mh¨���ÐÀ+_¤������'���vendor/symfony/process/ProcessUtils.php��è‰mh��ÓXì¤������"���vendor/symfony/process/Process.phpRh��è‰mhRh��­L„£¤������(���vendor/symfony/console/ConsoleEvents.phpÜ��è‰mhÜ��>cÅA¤������!���vendor/symfony/console/Cursor.php� ��è‰mh� ��Æ«§Ž¤������&���vendor/symfony/console/Application.phpq��è‰mhq��ým!„¤������/���vendor/symfony/console/Logger/ConsoleLogger.php ��è‰mh ��Ç Q¤������.���vendor/symfony/console/Attribute/AsCommand.phpÔ��è‰mhÔ��½3Üþ¤������9���vendor/symfony/console/Input/StreamableInputInterface.phpÎ���è‰mhÎ���ÖÕB›¤������+���vendor/symfony/console/Input/ArrayInput.php ��è‰mh ��ñ¦Ÿ.¤������*���vendor/symfony/console/Input/ArgvInput.php+��è‰mh+��F±¶Ñ¤������.���vendor/symfony/console/Input/InputArgument.php��è‰mh��ΠÀú¤������4���vendor/symfony/console/Input/InputAwareInterface.php˜���è‰mh˜���­O°¤������,���vendor/symfony/console/Input/InputOption.php��è‰mh��Iªž/¤������0���vendor/symfony/console/Input/InputDefinition.php#��è‰mh#�� Œ!3¤������,���vendor/symfony/console/Input/StringInput.php?��è‰mh?��±’ˤ������&���vendor/symfony/console/Input/Input.php¤ ��è‰mh¤ ��ÚÜo±¤������/���vendor/symfony/console/Input/InputInterface.phpü��è‰mhü��G¶ô¨¤������#���vendor/symfony/console/Terminal.phpm ��è‰mhm ��‡¥Pv¤������2���vendor/symfony/console/CI/GithubActionReporter.phpõ��è‰mhõ��¾Û"g¤������5���vendor/symfony/console/Output/TrimmedBufferOutput.phpÛ��è‰mhÛ��lkƒ~¤������8���vendor/symfony/console/Output/ConsoleOutputInterface.php��è‰mh��‰ê÷´¤������0���vendor/symfony/console/Output/BufferedOutput.phpl��è‰mhl��y:¸¤������1���vendor/symfony/console/Output/OutputInterface.phpí��è‰mhí��ð޾¤������(���vendor/symfony/console/Output/Output.phpÈ ��è‰mhÈ ��ŸË8x¤������6���vendor/symfony/console/Output/ConsoleSectionOutput.php” ��è‰mh” ��Àgo@¤������/���vendor/symfony/console/Output/ConsoleOutput.php‘ ��è‰mh‘ ��\Ýïb¤������,���vendor/symfony/console/Output/NullOutput.phpB��è‰mhB��%#RƤ������.���vendor/symfony/console/Output/StreamOutput.php¢��è‰mh¢��,¾"ü¤������A���vendor/symfony/console/Completion/Output/BashCompletionOutput.phpg��è‰mhg��‡ìùW¤������F���vendor/symfony/console/Completion/Output/CompletionOutputInterface.phpF��è‰mhF��Ô2nM¤������0���vendor/symfony/console/Completion/Suggestion.php3��è‰mh3��̆ ¤������;���vendor/symfony/console/Completion/CompletionSuggestions.phpÂ��è‰mhÂ��A¡¤������5���vendor/symfony/console/Completion/CompletionInput.php��è‰mh��”$„k¤������,���vendor/symfony/console/Style/OutputStyle.phpt��è‰mht��O;Ƥ������-���vendor/symfony/console/Style/SymfonyStyle.php5'��è‰mh5'��yl÷ô¤������/���vendor/symfony/console/Style/StyleInterface.php��è‰mh��\ž¤������2���vendor/symfony/console/Question/ChoiceQuestion.phpÝ
  110. ��è‰mhÝ
  111. �� c䦤������,���vendor/symfony/console/Question/Question.php" ��è‰mh" ��ÊÞ¹Û¤������8���vendor/symfony/console/Question/ConfirmationQuestion.php��è‰mh��îyÅ„¤������9���vendor/symfony/console/Formatter/OutputFormatterStyle.phpz��è‰mhz��ÿja­¤������B���vendor/symfony/console/Formatter/OutputFormatterStyleInterface.phpŸ��è‰mhŸ��ø€Äw¤������=���vendor/symfony/console/Formatter/NullOutputFormatterStyle.php ��è‰mh ��Ê0‡Ø¤������=���vendor/symfony/console/Formatter/OutputFormatterInterface.php£��è‰mh£��Y §ß¤������4���vendor/symfony/console/Formatter/OutputFormatter.php��è‰mh��Üæ¥¤������8���vendor/symfony/console/Formatter/NullOutputFormatter.php���è‰mh���!& u¤������F���vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.phpÖ���è‰mhÖ���¡Z·¤������>���vendor/symfony/console/Formatter/OutputFormatterStyleStack.php…��è‰mh…��LÙኤ������ ���vendor/symfony/console/Color.phph��è‰mhh��Gbç—¤������8���vendor/symfony/console/SignalRegistry/SignalRegistry.php!��è‰mh!��~.:¯¤������3���vendor/symfony/console/SingleCommandApplication.php7��è‰mh7��Í1¾¤������?���vendor/symfony/console/CommandLoader/CommandLoaderInterface.phpQ��è‰mhQ��›žH¤������?���vendor/symfony/console/CommandLoader/ContainerCommandLoader.phpU��è‰mhU��Ë_ü¤������=���vendor/symfony/console/CommandLoader/FactoryCommandLoader.php¯��è‰mh¯��d¼"z¤������4���vendor/symfony/console/Descriptor/TextDescriptor.phpç"��è‰mhç"��ȸÌˤ������<���vendor/symfony/console/Descriptor/ApplicationDescription.phpÙ ��è‰mhÙ ��çpC^¤������3���vendor/symfony/console/Descriptor/XmlDescriptor.php��è‰mh��uI@š¤������9���vendor/symfony/console/Descriptor/DescriptorInterface.php÷���è‰mh÷���µå@à¤������0���vendor/symfony/console/Descriptor/Descriptor.php}��è‰mh}��±ê3^¤������4���vendor/symfony/console/Descriptor/JsonDescriptor.phpë��è‰mhë��1%è�¤������8���vendor/symfony/console/Descriptor/MarkdownDescriptor.phpQ��è‰mhQ��t ˆv¤������/���vendor/symfony/console/Tester/CommandTester.phpÙ��è‰mhÙ��D¶¤������-���vendor/symfony/console/Tester/TesterTrait.php¬ ��è‰mh¬ ��2'L²¤������3���vendor/symfony/console/Tester/ApplicationTester.phpŒ��è‰mhŒ��Iû¤������9���vendor/symfony/console/Tester/CommandCompletionTester.phpÚ��è‰mhÚ��Ê›;°¤������@���vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.phpÖ��è‰mhÖ��ƃ‚¤������.���vendor/symfony/console/Command/LazyCommand.php›��è‰mh›��žmå¤������0���vendor/symfony/console/Command/LockableTrait.php��è‰mh��q5gj¤������.���vendor/symfony/console/Command/HelpCommand.php ��è‰mh ��}—¥¤������2���vendor/symfony/console/Command/CompleteCommand.php‹��è‰mh‹��¾}¤������.���vendor/symfony/console/Command/ListCommand.php1 ��è‰mh1 ��$D»|¤������8���vendor/symfony/console/Command/DumpCompletionCommand.php���è‰mh���9›9¤������=���vendor/symfony/console/Command/SignalableCommandInterface.phpÓ���è‰mhÓ���»B`¾¤������*���vendor/symfony/console/Command/Command.phpJ'��è‰mhJ'��� Úw¤������,���vendor/symfony/console/Helper/TableStyle.php���è‰mh���Wº¤������+���vendor/symfony/console/Helper/TableRows.php)��è‰mh)��WŠ3z¤������7���vendor/symfony/console/Helper/SymfonyQuestionHelper.php ��è‰mh ��à�dÿ¤������1���vendor/symfony/console/Helper/HelperInterface.phpæ���è‰mhæ���`RÂ\¤������+���vendor/symfony/console/Helper/TableCell.phpA��è‰mhA��èÓ ¤������/���vendor/symfony/console/Helper/ProcessHelper.php\ ��è‰mh\ ��ÄzA¤������0���vendor/symfony/console/Helper/TableSeparator.phpÅ���è‰mhÅ���¼õËü¤������1���vendor/symfony/console/Helper/FormatterHelper.phpi��è‰mhi��¤¶€w¤������0���vendor/symfony/console/Helper/TableCellStyle.phpî��è‰mhî��Ñ�¹_¤������-���vendor/symfony/console/Helper/ProgressBar.phpX/��è‰mhX/��2p’ä¤������6���vendor/symfony/console/Helper/DebugFormatterHelper.php¸��è‰mh¸��¤ð6 ¤������+���vendor/symfony/console/Helper/HelperSet.phpY��è‰mhY��¼…uA¤������(���vendor/symfony/console/Helper/Dumper.php��è‰mh��Ÿ<Ëߤ������2���vendor/symfony/console/Helper/InputAwareHelper.phpc��è‰mhc��Ìøƒ¤������0���vendor/symfony/console/Helper/QuestionHelper.phpR-��è‰mhR-��æ§1i¤������(���vendor/symfony/console/Helper/Helper.php� ��è‰mh� ��Á”1T¤������'���vendor/symfony/console/Helper/Table.php´J��è‰mh´J��S×Á­¤������3���vendor/symfony/console/Helper/ProgressIndicator.phpÀ��è‰mhÀ��‡Ëeõ¤������2���vendor/symfony/console/Helper/DescriptorHelper.phpÀ��è‰mhÀ��¦gÌ„¤������D���vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phpf��è‰mhf��#Ô $¤������3���vendor/symfony/console/Exception/LogicException.php’���è‰mh’���ÍO\e¤������;���vendor/symfony/console/Exception/InvalidOptionException.php¦���è‰mh¦���Ë×H¤������7���vendor/symfony/console/Exception/ExceptionInterface.phpy���è‰mhy���Ù9[&¤������5���vendor/symfony/console/Exception/RuntimeException.php–���è‰mh–���Ùí,6¤������?���vendor/symfony/console/Exception/NamespaceNotFoundException.php‹���è‰mh‹���‚ón©¤������=���vendor/symfony/console/Exception/InvalidArgumentException.php¦���è‰mh¦���Ö̽Z¤������:���vendor/symfony/console/Exception/MissingInputException.phpœ���è‰mhœ���æS
  112. þ¤������=���vendor/symfony/console/Exception/CommandNotFoundException.phpÛ��è‰mhÛ��K}ž¤������6���vendor/symfony/console/Event/ConsoleTerminateEvent.php~��è‰mh~��hr½Ö¤������2���vendor/symfony/console/Event/ConsoleErrorEvent.phpý��è‰mhý��é%˜¤������4���vendor/symfony/console/Event/ConsoleCommandEvent.phpÉ��è‰mhÉ��°Öá¤������-���vendor/symfony/console/Event/ConsoleEvent.phpÆ��è‰mhÆ��ÅoÛÙ¤������3���vendor/symfony/console/Event/ConsoleSignalEvent.phpG��è‰mhG��Žû ¤������6���vendor/symfony/console/EventListener/ErrorListener.php'��è‰mh'��𢡉¤������0���vendor/symfony/polyfill-mbstring/bootstrap80.php€%��è‰mh€%��o ¤������B���vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php•��è‰mh•��ô¶³ã¤������@���vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.phpùT��è‰mhùT��•±+¤������F���vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.phpã��è‰mhã��öy_•¤������@���vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php8[��è‰mh8[��+RØ*¤������-���vendor/symfony/polyfill-mbstring/Mbstring.phpõ^��è‰mhõ^��$Ý�-¤������.���vendor/symfony/polyfill-mbstring/bootstrap.phpm��è‰mhm��Oé; ¤������5���vendor/symfony/polyfill-intl-grapheme/bootstrap80.phpY ��è‰mhY ��¨! ¤������2���vendor/symfony/polyfill-intl-grapheme/Grapheme.phpÚ��è‰mhÚ��� ›¤������3���vendor/symfony/polyfill-intl-grapheme/bootstrap.phpÏ��è‰mhÏ��ý9À|¤������4���vendor/evenement/evenement/src/EventEmitterTrait.phpþ ��è‰mhþ ��w—´˜¤������8���vendor/evenement/evenement/src/EventEmitterInterface.php“��è‰mh“��íh,o¤������/���vendor/evenement/evenement/src/EventEmitter.phpŽ���è‰mhŽ���"®Êµ¤������'���vendor/react/event-loop/src/Factory.php…��è‰mh…��%^†¯¤������)���vendor/react/event-loop/src/ExtEvLoop.phpê��è‰mhê��Fs{¤������/���vendor/react/event-loop/src/ExtLibeventLoop.phpO��è‰mhO��¾,üÁ¤������,���vendor/react/event-loop/src/Timer/Timers.phpš��è‰mhš��4i£¤������+���vendor/react/event-loop/src/Timer/Timer.php���è‰mh���Ìw«¤������.���vendor/react/event-loop/src/SignalsHandler.phpä��è‰mhä��„»Ò¤������0���vendor/react/event-loop/src/StreamSelectLoop.php°��è‰mh°��¨Âw¤������,���vendor/react/event-loop/src/ExtEventLoop.php'��è‰mh'��‰nKq¤������.���vendor/react/event-loop/src/TimerInterface.php­���è‰mh­���}M7þ¤������-���vendor/react/event-loop/src/LoopInterface.php��è‰mh��#6Y'¤������$���vendor/react/event-loop/src/Loop.phpL
  113. ��è‰mhL
  114. ��ÍMþͤ������)���vendor/react/event-loop/src/ExtUvLoop.php4��è‰mh4��'/Ùd¤������,���vendor/react/event-loop/src/ExtLibevLoop.php8��è‰mh8��&Ó0*¤������4���vendor/react/event-loop/src/Tick/FutureTickQueue.phpÄ��è‰mhÄ��Ï%ä ¤������)���vendor/react/cache/src/CacheInterface.phpa��è‰mha��{¢·^¤������%���vendor/react/cache/src/ArrayCache.phpÜ ��è‰mhÜ ��5�ç¤������3���vendor/react/stream/src/WritableStreamInterface.phpP��è‰mhP��W …s¤������2���vendor/react/stream/src/WritableResourceStream.php| ��è‰mh| ��c‡�¤������3���vendor/react/stream/src/ReadableStreamInterface.phpŸ��è‰mhŸ��{ˆJ¤������2���vendor/react/stream/src/ReadableResourceStream.phpè ��è‰mhè ��M'ú¤������1���vendor/react/stream/src/DuplexStreamInterface.php����è‰mh����'ßM¤������)���vendor/react/stream/src/ThroughStream.php¡��è‰mh¡��¶ U’¤������ ���vendor/react/stream/src/Util.phpï��è‰mhï��©¬c/¤������+���vendor/react/stream/src/CompositeStream.phpà��è‰mhà��Ñ›6ã¤������0���vendor/react/stream/src/DuplexResourceStream.phpY��è‰mhY��þôŬ¤������-���vendor/react/promise/src/PromiseInterface.phpÆ��è‰mhÆ��ãµ {¤������&���vendor/react/promise/src/functions.phpÿ��è‰mhÿ��/�æ¤������.���vendor/react/promise/src/functions_include.php]���è‰mh]���QÑ<¡¤������$���vendor/react/promise/src/Promise.phpÈ��è‰mhÈ��Ö³ï¤������%���vendor/react/promise/src/Deferred.phpa��è‰mha��ª…U©¤������5���vendor/react/promise/src/Internal/RejectedPromise.php3��è‰mh3��Ôp N¤������6���vendor/react/promise/src/Internal/FulfilledPromise.php§��è‰mh§��TûÁN¤������7���vendor/react/promise/src/Internal/CancellationQueue.phpr��è‰mhr���x_±¤������6���vendor/react/promise/src/Exception/LengthException.php^���è‰mh^���?q¤������9���vendor/react/promise/src/Exception/CompositeException.phpŒ��è‰mhŒ��!ŒÏâ¤������0���vendor/react/dns/src/RecordNotFoundException.phpX���è‰mhX���Áykx¤������+���vendor/react/dns/src/BadServerException.phpS���è‰mhS���ž”%Z¤������&���vendor/react/dns/src/Config/Config.php@��è‰mh@��C*
  115. ¤������)���vendor/react/dns/src/Config/HostsFile.php��è‰mh��Ýñ�´¤������(���vendor/react/dns/src/Protocol/Parser.php²��è‰mh²��‘AÜž¤������.���vendor/react/dns/src/Protocol/BinaryDumper.php\��è‰mh\��%é í¤������%���vendor/react/dns/src/Model/Record.php±��è‰mh±��“¸O5¤������&���vendor/react/dns/src/Model/Message.php
  116. ��è‰mh
  117. ��©—ؤ������0���vendor/react/dns/src/Query/HostsFileExecutor.php��è‰mh��pÔ³¤������4���vendor/react/dns/src/Query/CancellationException.phpc���è‰mhc���׿kâ¤������3���vendor/react/dns/src/Query/TcpTransportExecutor.phpÑ��è‰mhÑ��‘¡ÿ¤������+���vendor/react/dns/src/Query/CoopExecutor.php}��è‰mh}��‚˜|ͤ������0���vendor/react/dns/src/Query/ExecutorInterface.php‹���è‰mh‹���Ï¡q$¤������9���vendor/react/dns/src/Query/SelectiveTransportExecutor.phpÃ��è‰mhÃ��‹­”2¤������/���vendor/react/dns/src/Query/FallbackExecutor.phpC��è‰mhC��F*"¶¤������3���vendor/react/dns/src/Query/UdpTransportExecutor.phpG��è‰mhG��æªx#¤������,���vendor/react/dns/src/Query/RetryExecutor.phpŠ��è‰mhŠ��g9°Ÿ¤������$���vendor/react/dns/src/Query/Query.php°��è‰mh°��$Hlj¤������.���vendor/react/dns/src/Query/TimeoutExecutor.phpå��è‰mhå��œÍ©œ¤������/���vendor/react/dns/src/Query/TimeoutException.phpW���è‰mhW���8À˜¤������.���vendor/react/dns/src/Query/CachingExecutor.php��è‰mh��ŒL�Ф������)���vendor/react/dns/src/Resolver/Factory.php5��è‰mh5��CÌП¤������*���vendor/react/dns/src/Resolver/Resolver.php+ ��è‰mh+ ��òÆ×—¤������3���vendor/react/dns/src/Resolver/ResolverInterface.phpé���è‰mhé���#æ¤������&���vendor/react/socket/src/Connection.phpî
  118. ��è‰mhî
  119. ��äADº¤������(���vendor/react/socket/src/DnsConnector.php@
  120. ��è‰mh@
  121. ��q”¨4¤������-���vendor/react/socket/src/FixedUriConnector.phpX��è‰mhX��—
  122. Â$¤������,���vendor/react/socket/src/StreamEncryption.php˜
  123. ��è‰mh˜
  124. ��Qz²¤������/���vendor/react/socket/src/ConnectionInterface.php<��è‰mh<��ècùk¤������+���vendor/react/socket/src/SecureConnector.phpm ��è‰mhm �� R\¤������"���vendor/react/socket/src/Server.phpZ��è‰mhZ��Ö9¤������$���vendor/react/socket/src/FdServer.phpÔ ��è‰mhÔ ��+ÇL.¤������(���vendor/react/socket/src/TcpConnector.phpØ ��è‰mhØ ��ø÷Ïà¤������(���vendor/react/socket/src/SecureServer.phpH ��è‰mhH ��±M¥¤������)���vendor/react/socket/src/UnixConnector.php¾��è‰mh¾��™¥I¤������&���vendor/react/socket/src/UnixServer.php4
  125. ��è‰mh4
  126. ��žƒ%Ô¤������:���vendor/react/socket/src/HappyEyeBallsConnectionBuilder.phpl��è‰mhl��€: ®¤������%���vendor/react/socket/src/TcpServer.phpn ��è‰mhn ��5÷.`¤������,���vendor/react/socket/src/TimeoutConnector.php3��è‰mh3��x턤������*���vendor/react/socket/src/LimitingServer.phpù��è‰mhù��õÛ÷´¤������%���vendor/react/socket/src/Connector.php‹��è‰mh‹��¶IÞ@¤������+���vendor/react/socket/src/ServerInterface.phpv��è‰mhv��ÒûÿÔ¤������(���vendor/react/socket/src/SocketServer.phpm ��è‰mhm ��¤ÂEg¤������2���vendor/react/socket/src/HappyEyeBallsConnector.phpª��è‰mhª��>™¿¤������.���vendor/react/socket/src/ConnectorInterface.php“���è‰mh“���ÅLݺ¤������*���vendor/react/child-process/src/Process.phpg��è‰mhg��CàèÕ¤������"���vendor/sebastian/diff/src/Diff.php+��è‰mh+��»tg/¤������$���vendor/sebastian/diff/src/Parser.phpª��è‰mhª��13[¤������M���vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.phpR��è‰mhR��H�Êê¤������:���vendor/sebastian/diff/src/Output/DiffOnlyOutputBuilder.phpŽ��è‰mhŽ��í&å¤������?���vendor/sebastian/diff/src/Output/DiffOutputBuilderInterface.php¬���è‰mh¬���2G\+¤������=���vendor/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php¢��è‰mh¢��bÇ\,¤������C���vendor/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php_��è‰mh_��1§ñ¤������?���vendor/sebastian/diff/src/Output/AbstractChunkOutputBuilder.phpD��è‰mhD��tH*‰¤������@���vendor/sebastian/diff/src/LongestCommonSubsequenceCalculator.php¸���è‰mh¸���Û/ò¤������#���vendor/sebastian/diff/src/Chunk.php¤��è‰mh¤��Ejt¤������$���vendor/sebastian/diff/src/Differ.php?��è‰mh?��Z¨·õ¤������"���vendor/sebastian/diff/src/Line.phpÕ��è‰mhÕ��öE_M¤������>���vendor/sebastian/diff/src/Exception/ConfigurationException.phpJ��è‰mhJ��?—Ýè¤������@���vendor/sebastian/diff/src/Exception/InvalidArgumentException.php¤���è‰mh¤���=Ò|ó¤������1���vendor/sebastian/diff/src/Exception/Exception.php„���è‰mh„���V›‰j¤������O���vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php��è‰mh��©j’v¤���������src/Finder.php��è‰mh��µ…˜t¤������3���src/Fixer/ClassNotation/ProtectedToPrivateFixer.php ��è‰mh ��ÎIk
  127. ¤������0���src/Fixer/ClassNotation/ClassDefinitionFixer.php±5��è‰mh±5�� Þ¤������?���src/Fixer/ClassNotation/SingleClassElementPerStatementFixer.phpT��è‰mhT��…‚tT¤������5���src/Fixer/ClassNotation/OrderedClassElementsFixer.php‹4��è‰mh‹4��9<¢¤������2���src/Fixer/ClassNotation/OrderedInterfacesFixer.php��è‰mh��ˆ}Ƥ������2���src/Fixer/ClassNotation/NoPhp4ConstructorFixer.php£��è‰mh£���Å‚=¤������3���src/Fixer/ClassNotation/FinalInternalClassFixer.phpP#��è‰mhP#��G/w¤������=���src/Fixer/ClassNotation/NoNullPropertyInitializationFixer.phpÑ ��è‰mhÑ ��«i¼è¤������+���src/Fixer/ClassNotation/FinalClassFixer.phpÿ��è‰mhÿ��YÄØ9¤������>���src/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixer.php��è‰mh��†öàW¤������6���src/Fixer/ClassNotation/NoUnneededFinalMethodFixer.php1��è‰mh1��šZ^¤������-���src/Fixer/ClassNotation/OrderedTypesFixer.php�&��è‰mh�&��‰Üà ¤������:���src/Fixer/ClassNotation/ClassAttributesSeparationFixer.phpÓ7��è‰mhÓ7��å—:†¤������.���src/Fixer/ClassNotation/OrderedTraitsFixer.phpâ��è‰mhâ��+ν~¤������-���src/Fixer/ClassNotation/SelfAccessorFixer.php¤��è‰mh¤��ÿ–’¤������B���src/Fixer/ClassNotation/FinalPublicMethodForAbstractClassFixer.phpl ��è‰mhl ��À £Ë¤������3���src/Fixer/ClassNotation/SelfStaticAccessorFixer.phpe��è‰mhe��À}�¤������3���src/Fixer/ClassNotation/VisibilityRequiredFixer.php<��è‰mh<��£*—î¤������D���src/Fixer/ClassNotation/PhpdocReadonlyClassCommentToKeywordFixer.phpv ��è‰mhv ��ð5/¤������4���src/Fixer/ClassNotation/StaticPrivateMethodFixer.php´��è‰mh´��Æþþ¤������>���src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.phpn��è‰mhn��g>õ�¤������9���src/Fixer/ControlStructure/NoUnneededCurlyBracesFixer.php��è‰mh��æ­Œ¤������7���src/Fixer/ControlStructure/NoAlternativeSyntaxFixer.php@��è‰mh@��ªÐ–G¤������-���src/Fixer/ControlStructure/YodaStyleFixer.phpG8��è‰mhG8��hèëø¤������6���src/Fixer/ControlStructure/EmptyLoopConditionFixer.php‘��è‰mh‘��–³w¤������>���src/Fixer/ControlStructure/SwitchCaseSemicolonToColonFixer.php��è‰mh��»³U¤������H���src/Fixer/ControlStructure/ControlStructureContinuationPositionFixer.phpŽ ��è‰mhŽ �� gFº¤������7���src/Fixer/ControlStructure/NoSuperfluousElseifFixer.phpB��è‰mhB��êÑÏç¤������3���src/Fixer/ControlStructure/SwitchCaseSpaceFixer.php#��è‰mh#��òpvº¤������4���src/Fixer/ControlStructure/NoUnneededBracesFixer.phpe��è‰mhe��Ç'I¤������1���src/Fixer/ControlStructure/EmptyLoopBodyFixer.php% ��è‰mh% ��/68¤������9���src/Fixer/ControlStructure/SwitchContinueToBreakFixer.php¦��è‰mh¦��nmb¤������6���src/Fixer/ControlStructure/SimplifiedIfReturnFixer.phpˆ
  128. ��è‰mhˆ
  129. ��°$TÙ¤������:���src/Fixer/ControlStructure/ControlStructureBracesFixer.phpÌ��è‰mhÌ��l6:Ĥ������1���src/Fixer/ControlStructure/NoUselessElseFixer.php`��è‰mh`��—ªƒ#¤������*���src/Fixer/ControlStructure/ElseifFixer.php·��è‰mh·��¶ º¤������<���src/Fixer/ControlStructure/TrailingCommaInMultilineFixer.php¥��è‰mh¥���¡v¤������+���src/Fixer/ControlStructure/IncludeFixer.php1��è‰mh1��äØ`ˆ¤������=���src/Fixer/ControlStructure/NoTrailingCommaInListCallFixer.php¿��è‰mh¿��üÉAM¤������@���src/Fixer/ControlStructure/NoUnneededControlParenthesesFixer.php§I��è‰mh§I��M»Á¶¤������2���src/Fixer/ControlStructure/NoBreakCommentFixer.php|#��è‰mh|#��ãã@¤������7���src/Fixer/FunctionNotation/RegularCallableCallFixer.php¾��è‰mh¾��‚Uê¤������7���src/Fixer/FunctionNotation/LambdaNotUsedImportFixer.php��è‰mh��5v)Ȥ������.���src/Fixer/FunctionNotation/VoidReturnFixer.php×��è‰mh×��M†Ã ¤������K���src/Fixer/FunctionNotation/NoTrailingCommaInSinglelineFunctionCallFixer.phpE��è‰mhE��ÏM0k¤������8���src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.phpa��è‰mha�� p°¤������0���src/Fixer/FunctionNotation/StaticLambdaFixer.php ��è‰mh ��Y¼¶V¤������9���src/Fixer/FunctionNotation/ReturnTypeDeclarationFixer.php6
  130. ��è‰mh6
  131. ��Ú³ ;¤������9���src/Fixer/FunctionNotation/FunctionTypehintSpaceFixer.php“��è‰mh“��YTáu¤������7���src/Fixer/FunctionNotation/MethodArgumentSpaceFixer.phpž1��è‰mhž1��¥´+ì¤������@���src/Fixer/FunctionNotation/DateTimeCreateFromFormatCallFixer.php���è‰mh���”"ð¤������4���src/Fixer/FunctionNotation/NoUselessSprintfFixer.php� ��è‰mh� ��(kh¤������2���src/Fixer/FunctionNotation/FopenFlagOrderFixer.phpÞ��è‰mhÞ��Iꮤ������8���src/Fixer/FunctionNotation/CombineNestedDirnameFixer.phpI��è‰mhI��ù²ÜS¤������=���src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.phpy ��è‰mhy ��Hoi¤������6���src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.phpæ��è‰mhæ��èŸ5†¤������<���src/Fixer/FunctionNotation/NativeFunctionInvocationFixer.phpï��è‰mhï��ãÈÁ“¤������.���src/Fixer/FunctionNotation/FopenFlagsFixer.php‚
  132. ��è‰mh‚
  133. ��¹ÖLE¤������N���src/Fixer/FunctionNotation/NullableTypeDeclarationForDefaultNullValueFixer.phpK��è‰mhK��’Ë<g¤������?���src/Fixer/FunctionNotation/MultilinePromotedPropertiesFixer.phpÖ��è‰mhÖ��Ÿ9’ž¤������E���src/Fixer/FunctionNotation/NoUnreachableDefaultArgumentValueFixer.php†��è‰mh†��pÀͤ������5���src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.phpÎ��è‰mhÎ��™*r÷¤������/���src/Fixer/FunctionNotation/ImplodeCallFixer.phpì ��è‰mhì ��HŽX¤������5���src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php× ��è‰mh× ��_›Ø÷¤������3���src/Fixer/FunctionNotation/SingleLineThrowFixer.php§ ��è‰mh§ ��àÑk¤������7���src/Fixer/FunctionNotation/FunctionDeclarationFixer.phpè��è‰mhè��ZK‚¤������0���src/Fixer/Phpdoc/GeneralPhpdocTagRenameFixer.phpó��è‰mhó��¬x›D¤������3���src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php¶��è‰mh¶��H”÷ý¤������9���src/Fixer/Phpdoc/PhpdocAddMissingParamAnnotationFixer.phpn��è‰mhn��Öÿ>¡¤������B���src/Fixer/Phpdoc/PhpdocTrimConsecutiveBlankLineSeparationFixer.phpÌ��è‰mhÌ��¾ƒ¨X¤������'���src/Fixer/Phpdoc/PhpdocTagTypeFixer.phpƒ��è‰mhƒ��ýÍcϤ������'���src/Fixer/Phpdoc/PhpdocSummaryFixer.php/��è‰mh/��gê»S¤������)���src/Fixer/Phpdoc/PhpdocNoPackageFixer.phpx��è‰mhx��À&®©¤������'���src/Fixer/Phpdoc/NoEmptyPhpdocFixer.phpY��è‰mhY��º”ä¤������(���src/Fixer/Phpdoc/PhpdocNoAccessFixer.phpi��è‰mhi��š9�Þ¤������&���src/Fixer/Phpdoc/PhpdocScalarFixer.php´��è‰mh´��N€÷¤������7���src/Fixer/Phpdoc/GeneralPhpdocAnnotationRemoveFixer.phpß ��è‰mhß ��âNñ'¤������,���src/Fixer/Phpdoc/PhpdocOrderByValueFixer.phpþ��è‰mhþ��`]0›¤������*���src/Fixer/Phpdoc/PhpdocParamOrderFixer.phpÎ��è‰mhÎ��`¯ºª¤������4���src/Fixer/Phpdoc/PhpdocAnnotationWithoutDotFixer.php÷ ��è‰mh÷ ��›Ì]g¤������(���src/Fixer/Phpdoc/PhpdocLineSpanFixer.php<��è‰mh<��÷Ü?¤������)���src/Fixer/Phpdoc/PhpdocTagCasingFixer.php¹��è‰mh¹��nO¤������/���src/Fixer/Phpdoc/AlignMultilineCommentFixer.phpo��è‰mho��8q½t¤������*���src/Fixer/Phpdoc/PhpdocNoAliasTagFixer.php� ��è‰mh� ��w~7
  134. ¤������*���src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php��è‰mh��ÞÐFï¤������$���src/Fixer/Phpdoc/PhpdocTrimFixer.phpø��è‰mhø��È–Ñš¤������9���src/Fixer/Phpdoc/PhpdocVarAnnotationCorrectOrderFixer.php~��è‰mh~��Ÿ¤½µ¤������4���src/Fixer/Phpdoc/PhpdocSingleLineVarSpacingFixer.phpó��è‰mhó��(惤������1���src/Fixer/Phpdoc/NoBlankLinesAfterPhpdocFixer.phpW��è‰mhW��ؑ췤������%���src/Fixer/Phpdoc/PhpdocTypesFixer.phpµ
  135. ��è‰mhµ
  136. ��=žÏ¤������-���src/Fixer/Phpdoc/PhpdocNoEmptyReturnFixer.php��è‰mh��Â�µ¬¤������*���src/Fixer/Phpdoc/PhpdocSeparationFixer.phpõ��è‰mhõ��q{À¤������(���src/Fixer/Phpdoc/PhpdocListTypeFixer.php¬��è‰mh¬��;t v¤������%���src/Fixer/Phpdoc/PhpdocOrderFixer.php ��è‰mh ��ÜM·i¤������3���src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php¨ ��è‰mh¨ ��ÅÏô¤������.���src/Fixer/Phpdoc/PhpdocVarWithoutNameFixer.php¢
  137. ��è‰mh¢
  138. ��Z¤Ê%¤������%���src/Fixer/Phpdoc/PhpdocAlignFixer.phph-��è‰mhh-��&<”¤������)���src/Fixer/Phpdoc/PhpdocToCommentFixer.phpŽ��è‰mhŽ��â¿ÿ®¤������)���src/Fixer/Phpdoc/PhpdocArrayTypeFixer.php%��è‰mh%��1c”¤������1���src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php{@��è‰mh{@��™2,#¤������&���src/Fixer/Phpdoc/PhpdocIndentFixer.php† ��è‰mh† ��ßâõ¤������3���src/Fixer/Phpdoc/PhpdocInlineTagNormalizerFixer.php2 ��è‰mh2 ��L!:¤������/���src/Fixer/ClassUsage/DateTimeImmutableFixer.phpÀ ��è‰mhÀ ��j½#M¤���������src/Fixer/FixerInterface.php;��è‰mh;��8™/ʤ������=���src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php$ ��è‰mh$ ��€1¬ý¤������=���src/Fixer/LanguageConstruct/ExplicitIndirectVariableFixer.phpÑ��è‰mhÑ��Bi�f¤������5���src/Fixer/LanguageConstruct/ErrorSuppressionFixer.phpŽ��è‰mhŽ��`«Ò£¤������:���src/Fixer/LanguageConstruct/DeclareEqualNormalizeFixer.phpö ��è‰mhö ��f±¼§¤������7���src/Fixer/LanguageConstruct/DeclareParenthesesFixer.phpÓ��è‰mhÓ��y¹’ñ¤������?���src/Fixer/LanguageConstruct/SingleSpaceAroundConstructFixer.phpj.��è‰mhj.��ôÍãë¤������7���src/Fixer/LanguageConstruct/FunctionToConstantFixer.phpþ��è‰mhþ��ë¤������>���src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.phpÝ��è‰mhÝ��ˆÕÚØ¤������1���src/Fixer/LanguageConstruct/ClassKeywordFixer.phpá��è‰mhá��À�Éò¤������<���src/Fixer/LanguageConstruct/NullableTypeDeclarationFixer.php‘ ��è‰mh‘ ��² ‚Ȥ������;���src/Fixer/LanguageConstruct/GetClassToClassKeywordFixer.php‹ ��è‰mh‹ ��4z…C¤������+���src/Fixer/LanguageConstruct/IsNullFixer.php��è‰mh��m”HÙ¤������=���src/Fixer/LanguageConstruct/CombineConsecutiveUnsetsFixer.php"��è‰mh"��ºòßL¤������0���src/Fixer/LanguageConstruct/DirConstantFixer.php¹ ��è‰mh¹ ��Ã;ÓU¤������7���src/Fixer/LanguageConstruct/ClassKeywordRemoveFixer.php@��è‰mh@��áK%è¤������6���src/Fixer/LanguageConstruct/NoUnsetOnPropertyFixer.phpô��è‰mhô�� ÕgN¤������,���src/Fixer/Alias/BacktickToShellExecFixer.php
  139. ��è‰mh
  140. ��NsÆè¤������"���src/Fixer/Alias/ArrayPushFixer.php0��è‰mh0��Ù¶¤������&���src/Fixer/Alias/SetTypeToCastFixer.phpZ��è‰mhZ��ßÛþ�¤������+���src/Fixer/Alias/RandomApiMigrationFixer.php
  141. ��è‰mh
  142. ��Ä ”¤������'���src/Fixer/Alias/MbStrFunctionsFixer.phpÅ��è‰mhÅ��_ið¤������)���src/Fixer/Alias/NoMixedEchoPrintFixer.phps ��è‰mhs ��]”¦¤������)���src/Fixer/Alias/NoAliasFunctionsFixer.php»��è‰mh»��#iܤ������5���src/Fixer/Alias/NoAliasLanguageConstructCallFixer.phpÂ��è‰mhÂ��StÁ¤������,���src/Fixer/Alias/PowToExponentiationFixer.php��è‰mh��üYH¤������(���src/Fixer/Alias/ModernizeStrposFixer.php
  143. "��è‰mh
  144. "��!c3¤������#���src/Fixer/Alias/EregToPregFixer.php& ��è‰mh& ��
  145. ¿˜ƒ¤������$���src/Fixer/ConfigurableFixerTrait.phpÈ
  146. ��è‰mhÈ
  147. ���X,¤������$���src/Fixer/InternalFixerInterface.php†���è‰mh†���Ô®Á¾¤���������src/Fixer/Indentation.phpf��è‰mhf��mÞþ¤������<���src/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixer.php˜ ��è‰mh˜ ��<ÀR¤������A���src/Fixer/NamespaceNotation/NoLeadingNamespaceWhitespaceFixer.php³��è‰mh³��©¬¤������C���src/Fixer/NamespaceNotation/SingleBlankLineBeforeNamespaceFixer.php4��è‰mh4��ÿHE¤������@���src/Fixer/NamespaceNotation/NoBlankLinesBeforeNamespaceFixer.phpó��è‰mhó���˜Ä´¤������3���src/Fixer/NamespaceNotation/CleanNamespaceFixer.phpß��è‰mhß��þi;š¤������>���src/Fixer/NamespaceNotation/BlankLinesBeforeNamespaceFixer.php$��è‰mh$��{ ïã¤������+���src/Fixer/CastNotation/NoUnsetCastFixer.phpR��è‰mhR��6�^U¤������*���src/Fixer/CastNotation/CastSpacesFixer.php— ��è‰mh— ��z« D¤������/���src/Fixer/CastNotation/NoShortBoolCastFixer.php1��è‰mh1��$Ý8C¤������/���src/Fixer/CastNotation/ShortScalarCastFixer.phpä��è‰mhä��? Á°¤������5���src/Fixer/CastNotation/ModernizeTypesCastingFixer.phpÝ ��è‰mhÝ ��³)™¤������-���src/Fixer/CastNotation/LowercaseCastFixer.phpÌ��è‰mhÌ��É%’«¤������&���src/Fixer/Casing/ConstantCaseFixer.php) ��è‰mh) ��“ˆsD¤������2���src/Fixer/Casing/ClassReferenceNameCasingFixer.php8��è‰mh8��뢤������2���src/Fixer/Casing/LowercaseStaticReferenceFixer.php#
  148. ��è‰mh#
  149. ��—ž0 ¤������,���src/Fixer/Casing/IntegerLiteralCaseFixer.php—��è‰mh—��e:ɤ������+���src/Fixer/Casing/LowercaseKeywordsFixer.php„��è‰mh„��'à;ƒ¤������=���src/Fixer/Casing/NativeFunctionTypeDeclarationCasingFixer.php���è‰mh���
  150. 9Ä'¤������-���src/Fixer/Casing/MagicConstantCasingFixer.phpÿ��è‰mhÿ��wXò\¤������+���src/Fixer/Casing/MagicMethodCasingFixer.phpH��è‰mhH��Øy…7¤������5���src/Fixer/Casing/NativeTypeDeclarationCasingFixer.phpö
  151. ��è‰mhö
  152. ��%\Ö¤������.���src/Fixer/Casing/NativeFunctionCasingFixer.phpg��è‰mhg��M']€¤������)���src/Fixer/Comment/NoEmptyCommentFixer.phpu ��è‰mhu ��>“òá¤������8���src/Fixer/Comment/NoTrailingWhitespaceInCommentFixer.phpÚ��è‰mhÚ��NÃÁ¤������(���src/Fixer/Comment/HeaderCommentFixer.php1��è‰mh1��ÿøè²¤������*���src/Fixer/Comment/CommentToPhpdocFixer.php½��è‰mh½��L0Š\¤������1���src/Fixer/Comment/SingleLineCommentStyleFixer.phpo ��è‰mho ��òÊï}¤������3���src/Fixer/Comment/SingleLineCommentSpacingFixer.phpº��è‰mhº��°á+¤������9���src/Fixer/Comment/MultilineCommentOpeningClosingFixer.php‹��è‰mh‹��K~3¤������2���src/Fixer/PhpTag/LinebreakAfterOpeningTagFixer.phpŽ��è‰mhŽ��ð¹^0¤������2���src/Fixer/PhpTag/BlankLineAfterOpeningTagFixer.phpŠ��è‰mhŠ��l+"ÿ¤������(���src/Fixer/PhpTag/FullOpeningTagFixer.php/ ��è‰mh/ ��_U(¤������&���src/Fixer/PhpTag/NoClosingTagFixer.phpÉ��è‰mhÉ��Ç{”÷¤������'���src/Fixer/PhpTag/EchoTagSyntaxFixer.phpÇ��è‰mhÇ��ó×L½¤������6���src/Fixer/ReturnNotation/SimplifiedNullReturnFixer.php~ ��è‰mh~ ��‹vØÞ¤������2���src/Fixer/ReturnNotation/ReturnAssignmentFixer.phpb,��è‰mhb,�� Wù¤������1���src/Fixer/ReturnNotation/NoUselessReturnFixer.phpð��è‰mhð��ÌóÝÛ¤������,���src/Fixer/AbstractIncrementOperatorFixer.phpç��è‰mhç��ƒ‚a-¤������&���src/Fixer/DeprecatedFixerInterface.php»���è‰mh»���Aµ‰¤������5���src/Fixer/Internal/ConfigurableFixerTemplateFixer.phpHC��è‰mhHC��K†®¤������,���src/Fixer/Basic/SingleLineEmptyBodyFixer.php®��è‰mh®�� %@~¤������4���src/Fixer/Basic/NoTrailingCommaInSinglelineFixer.php¸��è‰mh¸��"}˜î¤������'���src/Fixer/Basic/BracesPositionFixer.phpð0��è‰mhð0��2þL¤������!���src/Fixer/Basic/EncodingFixer.php}��è‰mh}��!0Ϥ������.���src/Fixer/Basic/NonPrintableCharacterFixer.phpµ��è‰mhµ��Ft#Q¤������,���src/Fixer/Basic/CurlyBracesPositionFixer.phpå��è‰mhå��…5:ž¤���������src/Fixer/Basic/BracesFixer.phph��è‰mhh��—µ¦<¤������'���src/Fixer/Basic/PsrAutoloadingFixer.phpÊ��è‰mhÊ��º‡mš¤������0���src/Fixer/Basic/NumericLiteralSeparatorFixer.phpv��è‰mhv��º�s¤������&���src/Fixer/Basic/OctalNotationFixer.php³��è‰mh³��é®:¤������4���src/Fixer/Basic/NoMultipleStatementsPerLineFixer.php��è‰mh��ãØü¤������,���src/Fixer/WhitespacesAwareFixerInterface.php��è‰mh�� ·‡Ú¤������6���src/Fixer/StringNotation/HeredocClosingMarkerFixer.phpÕ��è‰mhÕ��Oܬ¤������>���src/Fixer/StringNotation/NoTrailingWhitespaceInStringFixer.phpZ��è‰mhZ��0¼ùB¤������?���src/Fixer/StringNotation/SimpleToComplexStringVariableFixer.phpˆ��è‰mhˆ��NÕi¥¤������0���src/Fixer/StringNotation/NoBinaryStringFixer.phpß��è‰mhß��’(’a¤������8���src/Fixer/StringNotation/ExplicitStringVariableFixer.phpÕ��è‰mhÕ��zÓð°¤������1���src/Fixer/StringNotation/HeredocToNowdocFixer.phpC��è‰mhC��è&Ÿ@¤������5���src/Fixer/StringNotation/StringLengthToEmptyFixer.phpa��è‰mha��ï­ì!¤������-���src/Fixer/StringNotation/SingleQuoteFixer.php¥ ��è‰mh¥ ��Ÿ3_d¤������;���src/Fixer/StringNotation/StringImplicitBackslashesFixer.php.��è‰mh.��A#«¤������:���src/Fixer/StringNotation/MultilineStringToHeredocFixer.phpm��è‰mhm��pé[¾¤������;���src/Fixer/StringNotation/EscapeImplicitBackslashesFixer.phpL��è‰mhL��•&ê.¤������2���src/Fixer/StringNotation/StringLineEndingFixer.php¬��è‰mh¬��XÃ4¤������;���src/Fixer/AttributeNotation/GeneralAttributeRemoveFixer.phpÞ ��è‰mhÞ ��ÙçËÔ¤������>���src/Fixer/AttributeNotation/AttributeEmptyParenthesesFixer.php¹ ��è‰mh¹ ��û‹š¤������6���src/Fixer/AttributeNotation/OrderedAttributesFixer.phpò��è‰mhò��7Z
  153. °¤������C���src/Fixer/DoctrineAnnotation/DoctrineAnnotationIndentationFixer.phpt��è‰mht��|ÂÖ¤������G���src/Fixer/DoctrineAnnotation/DoctrineAnnotationArrayAssignmentFixer.php½��è‰mh½��£å38¤������>���src/Fixer/DoctrineAnnotation/DoctrineAnnotationSpacesFixer.phpW ��è‰mhW ��m(Ф������>���src/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixer.php ��è‰mh ��Õ>t�¤������*���src/Fixer/PhpUnit/PhpUnitTargetVersion.php‚��è‰mh‚��âMM¤������(���src/Fixer/PhpUnit/PhpUnitStrictFixer.phpþ ��è‰mhþ ��¶r¥F¤������0���src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php‚5��è‰mh‚5���ßϤ������+���src/Fixer/PhpUnit/PhpUnitConstructFixer.phpP��è‰mhP��Ȫ¤������9���src/Fixer/PhpUnit/PhpUnitSetUpTearDownVisibilityFixer.phpÓ��è‰mhÓ��ÛÊWĤ������0���src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php*'��è‰mh*'��5¥…�¤������,���src/Fixer/PhpUnit/PhpUnitAttributesFixer.phpz9��è‰mhz9��‘&Y\¤������8���src/Fixer/PhpUnit/PhpUnitDataProviderReturnTypeFixer.phpy
  154. ��è‰mhy
  155. ��tЄ_¤������+���src/Fixer/PhpUnit/PhpUnitSizeClassFixer.phpV ��è‰mhV ���@˜Ò¤������9���src/Fixer/PhpUnit/PhpUnitNoExpectationAnnotationFixer.phpº��è‰mhº��³”²o¤������<���src/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixer.phpZ��è‰mhZ��'þ¤������&���src/Fixer/PhpUnit/PhpUnitMockFixer.phpp��è‰mhp��ßßù¤������/���src/Fixer/PhpUnit/PhpUnitInternalClassFixer.php©
  156. ��è‰mh©
  157. ��rh“^¤������-���src/Fixer/PhpUnit/PhpUnitExpectationFixer.phpž��è‰mhž��Œ†êB¤������0���src/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixer.php¤��è‰mh¤��3)w¤������9���src/Fixer/PhpUnit/PhpUnitDataProviderMethodOrderFixer.php���è‰mh���7ìФ������,���src/Fixer/PhpUnit/PhpUnitNamespacedFixer.phpL��è‰mhL��$ešÜ¤������9���src/Fixer/PhpUnit/PhpUnitTestClassRequiresCoversFixer.phpq��è‰mhq��ûQãܤ������4���src/Fixer/PhpUnit/PhpUnitDataProviderStaticFixer.php£��è‰mh£��Ï(cþ¤������;���src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.phpš<��è‰mhš<��c—5 ¤������2���src/Fixer/PhpUnit/PhpUnitDataProviderNameFixer.phpe��è‰mhe��Or›Ç¤������5���src/Fixer/PhpUnit/PhpUnitMockShortWillReturnFixer.phpµ��è‰mhµ��ÆUº†¤������.���src/Fixer/PhpUnit/PhpUnitMethodCasingFixer.phpÈ��è‰mhÈ��=hĤ������0���src/Fixer/PhpUnit/PhpUnitAssertNewNamesFixer.phpR��è‰mhR��D¯Ç¤������(���src/Fixer/AbstractShortOperatorFixer.php¨��è‰mh¨��Ãø–|¤������(���src/Fixer/ConfigurableFixerInterface.phpÕ��è‰mhÕ��øÀe?¤������5���src/Fixer/Whitespace/CompactNullableTypehintFixer.php“��è‰mh“��wS¤������(���src/Fixer/Whitespace/LineEndingFixer.phpì��è‰mhì��Ön̵¤������2���src/Fixer/Whitespace/SingleBlankLineAtEofFixer.phpf��è‰mhf��go¡¼¤������-���src/Fixer/Whitespace/IndentationTypeFixer.phpŒ
  158. ��è‰mhŒ
  159. ��!+S¤������5���src/Fixer/Whitespace/SpacesInsideParenthesesFixer.phpL��è‰mhL��8ì/¤������.���src/Fixer/Whitespace/ArrayIndentationFixer.php7��è‰mh7���:Eɤ������2���src/Fixer/Whitespace/NoSpacesAroundOffsetFixer.phpw
  160. ��è‰mhw
  161. ��CR†¯¤������5���src/Fixer/Whitespace/NoWhitespaceInBlankLineFixer.phpå��è‰mhå��½íO­¤������3���src/Fixer/Whitespace/TypeDeclarationSpacesFixer.phpÓ��è‰mhÓ��«Ãt¤������6���src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php7��è‰mh7��åø>"¤������0���src/Fixer/Whitespace/HeredocIndentationFixer.phpÏ��è‰mhÏ��À¦Ô¤������)���src/Fixer/Whitespace/TypesSpacesFixer.php/��è‰mh/��š\÷̤������:���src/Fixer/Whitespace/BlankLineBetweenImportGroupsFixer.php£ ��è‰mh£ ��c™;¤������7���src/Fixer/Whitespace/NoSpacesInsideParenthesisFixer.phpm��è‰mhm��†{Sn¤������2���src/Fixer/Whitespace/NoTrailingWhitespaceFixer.phpÕ��è‰mhÕ���¡W%¤������<���src/Fixer/Whitespace/CompactNullableTypeDeclarationFixer.phpÛ��è‰mhÛ��Ö¤âH¤������7���src/Fixer/Whitespace/MethodChainingIndentationFixer.php=��è‰mh=��cì`¤������/���src/Fixer/Whitespace/NoExtraBlankLinesFixer.phpü%��è‰mhü%��ª-M9¤������2���src/Fixer/Whitespace/StatementIndentationFixer.phpŽM��è‰mhŽM��RU¬è¤������*���src/Fixer/Naming/NoHomoglyphNamesFixer.php ��è‰mh ��X˜~¤������,���src/Fixer/Strict/DeclareStrictTypesFixer.phpÁ
  162. ��è‰mhÁ
  163. ��¶9= ¤������*���src/Fixer/Strict/StrictComparisonFixer.phpð��è‰mhð��3JÙ¤������%���src/Fixer/Strict/StrictParamFixer.phpÞ��è‰mhÞ��™u7ˤ������C���src/Fixer/Semicolon/NoSinglelineWhitespaceBeforeSemicolonsFixer.phpU��è‰mhU��ZÖÆ¤������-���src/Fixer/Semicolon/NoEmptyStatementFixer.php}��è‰mh}��6áÏô¤������0���src/Fixer/Semicolon/SpaceAfterSemicolonFixer.phpC ��è‰mhC ��í–�‡¤������@���src/Fixer/Semicolon/MultilineWhitespaceBeforeSemicolonsFixer.php&��è‰mh&��°Ë°¤������6���src/Fixer/Semicolon/SemicolonAfterInstructionFixer.phpX��è‰mhX��mÓ<�¤������"���src/Fixer/AbstractPhpUnitFixer.phpü��è‰mhü��ẫ¤������3���src/Fixer/Import/FullyQualifiedStrictTypesFixer.phpÔY��è‰mhÔY���—œµ¤������)���src/Fixer/Import/NoUnusedImportsFixer.php¾*��è‰mh¾*��÷ìÝ5¤������/���src/Fixer/Import/GlobalNamespaceImportFixer.php�<��è‰mh�<��faµ¤������(���src/Fixer/Import/OrderedImportsFixer.php¨3��è‰mh¨3��F/)¤������/���src/Fixer/Import/NoUnneededImportAliasFixer.php'��è‰mh'���¸[K¤������2���src/Fixer/Import/SingleImportPerStatementFixer.php��è‰mh��ysj0¤������.���src/Fixer/Import/NoLeadingImportSlashFixer.phpú��è‰mhú��»ò›¶¤������%���src/Fixer/Import/GroupImportFixer.php$��è‰mh$��¥pl¤������0���src/Fixer/Import/SingleLineAfterImportsFixer.php³ ��è‰mh³ �� bt¬¤������,���src/Fixer/ArrayNotation/ArraySyntaxFixer.phpy ��è‰mhy ��Ê$å<¤������0���src/Fixer/ArrayNotation/TrimArraySpacesFixer.php
  164. ��è‰mh
  165. ��¥Ö�p¤������2���src/Fixer/ArrayNotation/ReturnToYieldFromFixer.phpS
  166. ��è‰mhS
  167. ��P3Û¤������?���src/Fixer/ArrayNotation/NoWhitespaceBeforeCommaInArrayFixer.phpz��è‰mhz��­¤|¤������G���src/Fixer/ArrayNotation/NoMultilineWhitespaceAroundDoubleArrowFixer.php ��è‰mh ��±�r�¤������7���src/Fixer/ArrayNotation/YieldFromArrayToYieldsFixer.phpƒ��è‰mhƒ��å}ZG¤������A���src/Fixer/ArrayNotation/NoTrailingCommaInSinglelineArrayFixer.php¿��è‰mh¿��O™dc¤������<���src/Fixer/ArrayNotation/WhitespaceAfterCommaInArrayFixer.php¨��è‰mh¨��¹o5°¤������4���src/Fixer/ArrayNotation/NormalizeIndexBraceFixer.phpº��è‰mhº��®ÆÂD¤������*���src/Fixer/ListNotation/ListSyntaxFixer.php ��è‰mh ��L/”)¤������4���src/Fixer/Operator/NewExpressionParenthesesFixer.php_��è‰mh_��>×ÂC¤������'���src/Fixer/Operator/ConcatSpaceFixer.phpô ��è‰mhô ��Fªsy¤������3���src/Fixer/Operator/LongToShorthandOperatorFixer.php;
  168. ��è‰mh;
  169. ��tÙHY¤������9���src/Fixer/Operator/NotOperatorWithSuccessorSpaceFixer.phpà��è‰mhà��aÝÆß¤������0���src/Fixer/Operator/BinaryOperatorSpacesFixer.phpöP��è‰mhöP��º@µw¤������1���src/Fixer/Operator/TernaryOperatorSpacesFixer.php
  170. ��è‰mh
  171. ��|Ïؤ������3���src/Fixer/Operator/TernaryToNullCoalescingFixer.php˜��è‰mh˜��"ÕÌ©¤������/���src/Fixer/Operator/UnaryOperatorSpacesFixer.php ��è‰mh ��FN¶—¤������2���src/Fixer/Operator/TernaryToElvisOperatorFixer.phpï��è‰mhï��ïÈøq¤������*���src/Fixer/Operator/IncrementStyleFixer.php/��è‰mh/��¡`-g¤������-���src/Fixer/Operator/OperatorLinebreakFixer.phpð��è‰mhð��¿�¤������.���src/Fixer/Operator/NewWithParenthesesFixer.phpÿ��è‰mhÿ��h)7¤������,���src/Fixer/Operator/LogicalOperatorsFixer.phpÄ��è‰mhÄ��pïø#¤������)���src/Fixer/Operator/NewWithBracesFixer.php��è‰mh��ü¯ö¥¤������?���src/Fixer/Operator/AssignNullCoalescingToCoalesceEqualFixer.php¨��è‰mh¨��î®Xj¤������;���src/Fixer/Operator/ObjectOperatorWithoutWhitespaceFixer.phpx��è‰mhx��‡q¤������5���src/Fixer/Operator/NoUselessNullsafeOperatorFixer.phpÊ��è‰mhÊ��¿H¤������3���src/Fixer/Operator/NoUselessConcatOperatorFixer.phpÛ!��è‰mhÛ!��Œ8GV¤������0���src/Fixer/Operator/StandardizeIncrementFixer.php˜��è‰mh˜��'sêö¤������0���src/Fixer/Operator/StandardizeNotEqualsFixer.phpª��è‰mhª�� Ѱû¤������0���src/Fixer/Operator/NotOperatorWithSpaceFixer.php¡��è‰mh¡��M‰vÖ¤������4���src/Fixer/Operator/NoSpaceAroundDoubleColonFixer.php7��è‰mh7��;«ù¤������<���src/Fixer/ConstantNotation/NativeConstantInvocationFixer.php��è‰mh��4¥c\¤������(���src/Fixer/ExperimentalFixerInterface.phpŠ���è‰mhŠ���d2‚þ¤������B���src/ConfigurationException/RequiredFixerConfigurationException.php¼���è‰mh¼���PͪS¤������G���src/ConfigurationException/InvalidForEnvFixerConfigurationException.phpÁ���è‰mhÁ���4¿œH¤������<���src/ConfigurationException/InvalidConfigurationException.phpÆ��è‰mhÆ��VÝwT¤������A���src/ConfigurationException/InvalidFixerConfigurationException.phpn��è‰mhn��ƒƒ"÷¤������*���src/Documentation/DocumentationLocator.phpp��è‰mhp�� ßþ¤������3���src/Documentation/RuleSetDocumentationGenerator.phps��è‰mhs��ÄÔq¤���������src/Documentation/RstUtils.php ��è‰mh ��òÌ#%¤������,���src/Documentation/FixerDocumentGenerator.phpÑ+��è‰mhÑ+��âĘb¤���������src/RuleSet/RuleSets.php
  172. ��è‰mh
  173. ��QaD¤������ ���src/RuleSet/RuleSetInterface.php=��è‰mh=�� ¯Ìf¤������+���src/RuleSet/RuleSetDescriptionInterface.php��è‰mh��f¦I¤���������src/RuleSet/RuleSet.php@ ��è‰mh@ ��Pq&_¤������5���src/RuleSet/DeprecatedRuleSetDescriptionInterface.php×���è‰mh×���è�µ,¤������/���src/RuleSet/Sets/PHPUnit32MigrationRiskySet.phpÄ��è‰mhÄ��ñÇÙ4¤������&���src/RuleSet/Sets/PHP80MigrationSet.phpV��è‰mhV��ôʲԤ������$���src/RuleSet/Sets/SymfonyRiskySet.php‚��è‰mh‚��ϳRf¤������"���src/RuleSet/Sets/PhpCsFixerSet.phpg
  174. ��è‰mhg
  175. ��í5¡h¤���������src/RuleSet/Sets/PSR2Set.phpf��è‰mhf��à¸éf¤������+���src/RuleSet/Sets/PHP71MigrationRiskySet.phpD��è‰mhD��hÒ¤������+���src/RuleSet/Sets/PHP82MigrationRiskySet.phpa��è‰mha��×}8¤������/���src/RuleSet/Sets/PHPUnit56MigrationRiskySet.php��è‰mh��–�:­¤������&���src/RuleSet/Sets/PHP54MigrationSet.php��è‰mh��SmÚž¤������&���src/RuleSet/Sets/PHP70MigrationSet.phpH��è‰mhH��…ì¤������+���src/RuleSet/Sets/PHP74MigrationRiskySet.php‚��è‰mh‚��Cɪì¤������ ���src/RuleSet/Sets/PERCS1x0Set.phpØ��è‰mhØ��q¤ Ǥ���������src/RuleSet/Sets/SymfonySet.php†��è‰mh†��SV,y¤���������src/RuleSet/Sets/PERCSSet.phpï��è‰mhï��ÌØ|Y¤���������src/RuleSet/Sets/PSR12Set.php��è‰mh��ÐÒ9¤������&���src/RuleSet/Sets/PHP71MigrationSet.phpX��è‰mhX��ýBò¤������/���src/RuleSet/Sets/PHPUnit84MigrationRiskySet.phpÛ��è‰mhÛ��Ò‘¸\¤������&���src/RuleSet/Sets/PHP81MigrationSet.php<��è‰mh<��¿êß,¤������/���src/RuleSet/Sets/PHPUnit60MigrationRiskySet.phpµ��è‰mhµ��@qý<¤������/���src/RuleSet/Sets/PHPUnit57MigrationRiskySet.phpµ��è‰mhµ��F�§î¤������+���src/RuleSet/Sets/PHP70MigrationRiskySet.phpû��è‰mhû��áž(L¤������ ���src/RuleSet/Sets/PERRiskySet.phpÎ��è‰mhÎ��„(¶�¤������/���src/RuleSet/Sets/PHPUnit52MigrationRiskySet.php¶��è‰mh¶��îX3ä������*���src/RuleSet/Sets/DoctrineAnnotationSet.phpj��è‰mhj��ŠÈSñ¤������ ���src/RuleSet/Sets/PERCS2x0Set.phpÉ��è‰mhÉ��Z`ê¤������'���src/RuleSet/Sets/PhpCsFixerRiskySet.php©��è‰mh©��4‰°¡¤������&���src/RuleSet/Sets/PHP73MigrationSet.php÷��è‰mh÷��O9˜¤������+���src/RuleSet/Sets/PHP80MigrationRiskySet.php��è‰mh��›Ã¹‡¤������/���src/RuleSet/Sets/PHPUnit54MigrationRiskySet.php¯��è‰mh¯��$[v¤������&���src/RuleSet/Sets/PHP84MigrationSet.php^��è‰mh^��Á»–¤������"���src/RuleSet/Sets/PERCSRiskySet.php��è‰mh��ÚØ¤������/���src/RuleSet/Sets/PHPUnit35MigrationRiskySet.phpº��è‰mhº��pñµ¤������&���src/RuleSet/Sets/PHP83MigrationSet.php"��è‰mh"��VˆÍ‹¤������+���src/RuleSet/Sets/PHP56MigrationRiskySet.php-��è‰mh-��Ãþ·º¤������/���src/RuleSet/Sets/PHPUnit30MigrationRiskySet.php•��è‰mh•��ѽn¤������0���src/RuleSet/Sets/PHPUnit100MigrationRiskySet.phpl��è‰mhl��“êˆÂ¤������/���src/RuleSet/Sets/PHPUnit43MigrationRiskySet.phpÄ��è‰mhÄ��ª&�æ¤������&���src/RuleSet/Sets/PHP74MigrationSet.php”��è‰mh”���q¸Ú¤���������src/RuleSet/Sets/PSR1Set.php¥��è‰mh¥��o¥ì¤������/���src/RuleSet/Sets/PHPUnit91MigrationRiskySet.phpZ��è‰mhZ��½Çˆ®¤������"���src/RuleSet/Sets/PSR12RiskySet.phpÚ��è‰mhÚ��f¤������&���src/RuleSet/Sets/PHP82MigrationSet.phpO��è‰mhO��`Ý&¤������%���src/RuleSet/Sets/PERCS2x0RiskySet.phpí��è‰mhí��ÆGãÙ¤������/���src/RuleSet/Sets/PHPUnit50MigrationRiskySet.phpº��è‰mhº��³¥d¤���������src/RuleSet/Sets/PERSet.phpu��è‰mhu��R—Zޤ������/���src/RuleSet/Sets/PHPUnit55MigrationRiskySet.php¯��è‰mh¯��Î �>¤������%���src/RuleSet/Sets/PERCS1x0RiskySet.phpé��è‰mhé��Ë zî¤������/���src/RuleSet/Sets/PHPUnit75MigrationRiskySet.phpÈ��è‰mhÈ��ÛÛ/Œ¤������/���src/RuleSet/Sets/PHPUnit48MigrationRiskySet.phpµ��è‰mhµ��1
  176. l½¤������*���src/RuleSet/AbstractRuleSetDescription.php´��è‰mh´��árEɤ������/���src/RuleSet/AbstractMigrationSetDescription.phpÐ��è‰mhÐ��ûåu¤������"���src/AbstractNoUselessElseFixer.php‡ ��è‰mh‡ ��Ú̼ž¤���������src/Cache/FileHandler.phpª ��è‰mhª ��zÁ÷ý¤���������src/Cache/FileCacheManager.php ��è‰mh ��ÈéÂö¤���������src/Cache/Cache.php%
  177. ��è‰mh%
  178. ��Oš¤���������src/Cache/CacheInterface.php|��è‰mh|��¹?Õ¤���������src/Cache/NullCacheManager.phpl��è‰mhl��‡âè�¤������#���src/Cache/CacheManagerInterface.php9��è‰mh9��M>㊤������"���src/Cache/FileHandlerInterface.phpò���è‰mhò���Ì
  179. �~¤���������src/Cache/Directory.php ��è‰mh ��†'•A¤������ ���src/Cache/SignatureInterface.phpj��è‰mhj��)wvå¤������ ���src/Cache/DirectoryInterface.php¥���è‰mh¥���óž…¤���������src/Cache/Signature.phpã��è‰mhã��FWͺ¤������#���src/Linter/ProcessLintingResult.phpî��è‰mhî��lcrÿ¤������%���src/Linter/LintingResultInterface.php“���è‰mh“���Wªô/¤���������src/Linter/ProcessLinter.phpà
  180. ��è‰mhà
  181. ��¼�>$¤������%���src/Linter/TokenizerLintingResult.php‚��è‰mh‚��-õý¤������)���src/Linter/UnavailableLinterException.php����è‰mh����ûbŽç¤���������src/Linter/LintingException.php„���è‰mh„���|� €¤������*���src/Linter/ProcessLinterProcessBuilder.php’��è‰mh’��¤Í}Ò¤���������src/Linter/LinterInterface.php��è‰mh��˜«´8¤���������src/Linter/Linter.php0��è‰mh0��üÇ ¤���������src/Linter/TokenizerLinter.php×��è‰mh×��ß'¤���������src/Linter/CachingLinter.php���è‰mh���Ã¥¼x¤���������src/PregException.php€���è‰mh€���ëN牤���������src/ConfigInterface.phpj��è‰mhj��ú¬¡E¤���������src/FileReader.php?��è‰mh?��b«ÔϤ������ ���src/AbstractPhpdocTypesFixer.phpó��è‰mhó��^j£g¤������ ���src/Tokenizer/TokensAnalyzer.phpGH��è‰mhGH��Q õ ¤���������src/Tokenizer/Tokens.php©j��è‰mh©j��ÃÅI,¤���������src/Tokenizer/Token.phph!��è‰mhh!��¶—�Þ¤���������src/Tokenizer/FCT.php?��è‰mh?��G¥¹ø¤������6���src/Tokenizer/Transformer/NameQualifiedTransformer.phpú��è‰mhú��J^É"¤������6���src/Tokenizer/Transformer/ArrayTypehintTransformer.php��è‰mh��,Ùê¤������/���src/Tokenizer/Transformer/ImportTransformer.phpJ��è‰mhJ��¨½ñ=¤������4���src/Tokenizer/Transformer/SquareBraceTransformer.phph��è‰mhh��ÈÏòû¤������2���src/Tokenizer/Transformer/TypeColonTransformer.phpO��è‰mhO��1à×ÿ¤������2���src/Tokenizer/Transformer/ReturnRefTransformer.php®��è‰mh®��8îæ·¤������:���src/Tokenizer/Transformer/WhitespacyCommentTransformer.phpø��è‰mhø��â�Ey¤������;���src/Tokenizer/Transformer/FirstClassCallableTransformer.php��è‰mh��–~™¤������:���src/Tokenizer/Transformer/NamespaceOperatorTransformer.php
  182. ��è‰mh
  183. ��Üìðy¤������.���src/Tokenizer/Transformer/BraceTransformer.phpê��è‰mhê��½¶~U¤������5���src/Tokenizer/Transformer/NullableTypeTransformer.php­��è‰mh­��w¼†¤¤������M���src/Tokenizer/Transformer/DisjunctiveNormalFormTypeParenthesisTransformer.phpB��è‰mhB��v¡f¤������9���src/Tokenizer/Transformer/TypeIntersectionTransformer.php)��è‰mh)��s>Ÿ$¤������8���src/Tokenizer/Transformer/TypeAlternationTransformer.phpû��è‰mhû�� [Û¤������2���src/Tokenizer/Transformer/AttributeTransformer.phpQ��è‰mhQ��ý¢¤������@���src/Tokenizer/Transformer/BraceClassInstantiationTransformer.php7��è‰mh7��ÆbÆ@¤������6���src/Tokenizer/Transformer/ClassConstantTransformer.php=��è‰mh=��~[œÍ¤������,���src/Tokenizer/Transformer/UseTransformer.phpa��è‰mha��èӺ¤������6���src/Tokenizer/Transformer/NamedArgumentTransformer.php<��è‰mh<��lq镤������=���src/Tokenizer/Transformer/ConstructorPromotionTransformer.php»��è‰mh»��Û³v=¤������+���src/Tokenizer/Processor/ImportProcessor.phpú��è‰mhú��—Q'®¤������)���src/Tokenizer/AbstractTypeTransformer.phpk��è‰mhk��.S¡_¤���������src/Tokenizer/Transformers.phpD��è‰mhD��q­%¤������&���src/Tokenizer/TransformerInterface.php…��è‰mh…��·¶¡¤������%���src/Tokenizer/AbstractTransformer.phpÐ��è‰mhÐ��wì'¡¤������/���src/Tokenizer/Analyzer/DataProviderAnalyzer.php8��è‰mh8��!Aß–¤������,���src/Tokenizer/Analyzer/ReferenceAnalyzer.phpà��è‰mhà��PCLo¤������1���src/Tokenizer/Analyzer/Analysis/MatchAnalysis.php��è‰mh�� ‚‡Â¤������2���src/Tokenizer/Analyzer/Analysis/SwitchAnalysis.php„��è‰mh„��^9bJ¤������5���src/Tokenizer/Analyzer/Analysis/AttributeAnalysis.php ��è‰mh ��”2ï…¤������8���src/Tokenizer/Analyzer/Analysis/NamespaceUseAnalysis.php ��è‰mh ��÷{ž;¤������I���src/Tokenizer/Analyzer/Analysis/AbstractControlCaseStructuresAnalysis.php$��è‰mh$��îXŒ¤������8���src/Tokenizer/Analyzer/Analysis/DataProviderAnalysis.php¢��è‰mh¢��kaQU¤������>���src/Tokenizer/Analyzer/Analysis/StartEndTokenAwareAnalysis.phpë���è‰mhë���oQ6,¤������0���src/Tokenizer/Analyzer/Analysis/TypeAnalysis.phpû��è‰mhû��Ç…J:¤������3���src/Tokenizer/Analyzer/Analysis/DefaultAnalysis.php³��è‰mh³��x„<÷¤������5���src/Tokenizer/Analyzer/Analysis/NamespaceAnalysis.phpÂ��è‰mhÂ��’ ˆ¤������0���src/Tokenizer/Analyzer/Analysis/EnumAnalysis.php­��è‰mh­��êv™¤������0���src/Tokenizer/Analyzer/Analysis/CaseAnalysis.php²��è‰mh²��Hšç
  184. ¤������4���src/Tokenizer/Analyzer/Analysis/ArgumentAnalysis.php¸��è‰mh¸��íý¤������8���src/Tokenizer/Analyzer/ControlCaseStructuresAnalyzer.php��è‰mh��`�ùݤ������)���src/Tokenizer/Analyzer/BlocksAnalyzer.phpÜ��è‰mhÜ��-%W“¤������,���src/Tokenizer/Analyzer/GotoLabelAnalyzer.phpg��è‰mhg��@Ÿå¤������5���src/Tokenizer/Analyzer/FullyQualifiedNameAnalyzer.php¼��è‰mh¼��°òò¤������,���src/Tokenizer/Analyzer/FunctionsAnalyzer.php6��è‰mh6��!(ò"¤������-���src/Tokenizer/Analyzer/NamespacesAnalyzer.phpy ��è‰mhy ��Ô#{í¤������,���src/Tokenizer/Analyzer/ArgumentsAnalyzer.php2 ��è‰mh2 ��æZ\W¤������4���src/Tokenizer/Analyzer/AlternativeSyntaxAnalyzer.php
  185. ��è‰mh
  186. ��_€áñ¤������(���src/Tokenizer/Analyzer/RangeAnalyzer.php‰��è‰mh‰��páÆ¶¤������0���src/Tokenizer/Analyzer/NamespaceUsesAnalyzer.php���è‰mh���é?™¤������)���src/Tokenizer/Analyzer/ClassyAnalyzer.php��è‰mh��L¨Ÿ¤������)���src/Tokenizer/Analyzer/SwitchAnalyzer.php²��è‰mh²��t¬L¤������2���src/Tokenizer/Analyzer/PhpUnitTestCaseAnalyzer.phpß��è‰mhß��–‡Ȥ������.���src/Tokenizer/Analyzer/WhitespacesAnalyzer.php��è‰mh��û¦–Œ¤������+���src/Tokenizer/Analyzer/CommentsAnalyzer.phpÆ��è‰mhÆ��ô¡Ϥ������,���src/Tokenizer/Analyzer/AttributeAnalyzer.php÷��è‰mh÷��…ìBœ¤���������src/Tokenizer/CT.phpó
  187. ��è‰mhó
  188. ��ÀxyÛ¤������'���src/AbstractDoctrineAnnotationFixer.phpY��è‰mhY��£„lù¤������&���src/Runner/Parallel/ParallelConfig.phpþ��è‰mhþ��Rê,ͤ������)���src/Runner/Parallel/ProcessIdentifier.phpÜ��è‰mhÜ��"ƒ
  189. •¤������&���src/Runner/Parallel/ProcessFactory.php.��è‰mh.��
  190. ¸U¤������&���src/Runner/Parallel/ParallelAction.phpµ��è‰mhµ��ûçáì¤������'���src/Runner/Parallel/WorkerException.phpù��è‰mhù��(HÍ<¤������-���src/Runner/Parallel/ParallelConfigFactory.phpí��è‰mhí��Q;¼Ú¤������#���src/Runner/Parallel/ProcessPool.php³��è‰mh³��Ä£��¤������0���src/Runner/Parallel/ParallelisationException.php:��è‰mh:��a±
  191. ¤���������src/Runner/Parallel/Process.php ��è‰mh ��mg�7¤������6���src/Runner/LintingResultAwareFileIteratorInterface.php��è‰mh��1Ðwó¤���������src/Runner/RunnerConfig.phpn��è‰mhn��q(õø¤������!���src/Runner/FileFilterIterator.phpÛ��è‰mhÛ��|„�U¤������"���src/Runner/LintingFileIterator.php���è‰mh���éY…¤������-���src/Runner/FileCachingLintingFileIterator.phpã��è‰mhã��¬| Ȥ������"���src/Runner/Event/FileProcessed.php¥��è‰mh¥�� lÐ~¤������$���src/Runner/Event/AnalysisStarted.phpI��è‰mhI��œÐͤ���������src/Runner/Runner.php82��è‰mh82��yÿǤ������-���src/FixerConfiguration/AllowedValueSubset.phpb��è‰mhb��H†E'¤������5���src/FixerConfiguration/FixerConfigurationResolver.php ��è‰mh ��
  192. š.Ȥ������9���src/FixerConfiguration/DeprecatedFixerOptionInterface.phpÐ���è‰mhÐ���˜â`Ĥ������&���src/FixerConfiguration/FixerOption.php1��è‰mh1��ߌÙܤ������/���src/FixerConfiguration/FixerOptionInterface.php›��è‰mh›��=¨kê¤������,���src/FixerConfiguration/FixerOptionSorter.php‰��è‰mh‰��+L
  193.  ¤������-���src/FixerConfiguration/FixerOptionBuilder.phpî��è‰mhî��:€·¤������8���src/FixerConfiguration/InvalidOptionsForEnvException.phpñ���è‰mhñ���éôì¤������-���src/FixerConfiguration/AliasedFixerOption.php��è‰mh�� ŠÍ•¤������4���src/FixerConfiguration/AliasedFixerOptionBuilder.phpá��è‰mhá��¥;â¤������>���src/FixerConfiguration/FixerConfigurationResolverInterface.phpë���è‰mhë���Lïp¤������0���src/FixerConfiguration/DeprecatedFixerOption.php9��è‰mh9���-å¤������,���src/ExecutorWithoutErrorHandlerException.php•���è‰mh•���™X ^¤������$���src/ParallelAwareConfigInterface.php<��è‰mh<��˜I¼¤���������src/AbstractFopenFlagFixer.phpü��è‰mhü��Ü^ù‰¤���������src/PharChecker.php¹��è‰mh¹���¯<¢¤���������src/Differ/FullDiffer.phpw��è‰mhw��}Yù¤������#���src/Differ/DiffConsoleFormatter.php ��è‰mh ��ýÖ¹:¤���������src/Differ/DifferInterface.phpÁ���è‰mhÁ���̇G¤���������src/Differ/NullDiffer.phpä���è‰mhä���ž-ž‰¤���������src/Differ/UnifiedDiffer.phpÅ��è‰mhÅ��°h:¤���������src/FixerNameValidator.php6��è‰mh6��2v ¤���������src/Config.phpý��è‰mhý��ˆŸrz¤������3���src/UnsupportedPhpVersionAllowedConfigInterface.php<��è‰mh<��$Uo;¤������"���src/Doctrine/Annotation/Tokens.phpï��è‰mhï��õ9Z’¤������!���src/Doctrine/Annotation/Token.php‹��è‰mh‹��ùŸC«¤������$���src/Doctrine/Annotation/DocLexer.phpè
  194. ��è‰mhè
  195. ��:åÙõ¤������#���src/ExecutorWithoutErrorHandler.phpI��è‰mhI��óù!¤���������src/WordMatcher.php(��è‰mh(��‡˜ ¤���������src/AbstractProxyFixer.phpp��è‰mhp��éÊï¤���������src/StdinFileInfo.php±��è‰mh±��ÄÎ^¤���������src/DocBlock/Tag.phpâ��è‰mhâ��ÒPö¤���������src/DocBlock/TagComparator.php,��è‰mh,��ÿ¹nR¤���������src/DocBlock/Annotation.phpÉ��è‰mhÉ��®¯ã³¤���������src/DocBlock/TypeExpression.phpËV��è‰mhËV��j\Ö¤������!���src/DocBlock/ShortDescription.phpC��è‰mhC��A«æë¤���������src/DocBlock/DocBlock.php¾��è‰mh¾��1Áb¤���������src/DocBlock/Line.phpz��è‰mhz��ò{hݤ������"���src/FixerDefinition/CodeSample.phpì��è‰mhì��/�˜¤������+���src/FixerDefinition/CodeSampleInterface.phpÊ���è‰mhÊ����¬[¤������:���src/FixerDefinition/VersionSpecificCodeSampleInterface.phpÕ���è‰mhÕ���±»4=¤������'���src/FixerDefinition/FixerDefinition.phpk��è‰mhk��dá9¤������.���src/FixerDefinition/FileSpecificCodeSample.phpÊ��è‰mhÊ��ÌŠüp¤������5���src/FixerDefinition/VersionSpecificationInterface.php´���è‰mh´���|@��¤������0���src/FixerDefinition/FixerDefinitionInterface.php1��è‰mh1��‚þ÷ݤ������1���src/FixerDefinition/VersionSpecificCodeSample.php9��è‰mh9��±ÀüI¤������,���src/FixerDefinition/VersionSpecification.php„��è‰mh„��éˆޤ������7���src/FixerDefinition/FileSpecificCodeSampleInterface.phpÑ���è‰mhÑ���¹Ñ¤���������src/FixerFactory.php©��è‰mh©��ÄqZb¤������ ���src/Utils.phpV��è‰mhV��ÇÀ'U¤���������src/ToolInfoInterface.php½��è‰mh½��½·¤������,���src/AbstractPhpdocToTypeDeclarationFixer.php„��è‰mh„��öÅt¤���������src/WhitespacesFixerConfig.php��è‰mh��ÎèÌç¤���������src/AbstractFixer.php}��è‰mh}��¸‘焤������ ���src/Preg.php��è‰mh��©Ù‚ž¤���������src/Error/Error.php…��è‰mh…��ÿæö”¤������$���src/Error/SourceExceptionFactory.php��è‰mh��"€Øõ¤���������src/Error/ErrorsManager.php´��è‰mh´��¡P{o¤������&���src/AbstractFunctionReferenceFixer.php²��è‰mh²��çm5ë¤���������src/Hasher.php ��è‰mh ��ïõ‹·¤���������src/ToolInfo.phpá��è‰mhá��!¶Ä¤���������src/Console/Application.phpÇ��è‰mhÇ��{d4ˆ¤������5���src/Console/SelfUpdate/NewVersionCheckerInterface.phpH��è‰mhH��í£…¤������0���src/Console/SelfUpdate/GithubClientInterface.php¡���è‰mh¡���¢n3 ¤������'���src/Console/SelfUpdate/GithubClient.php–��è‰mh–��Í„^¤������,���src/Console/SelfUpdate/NewVersionChecker.php ��è‰mh ��ñ‘¹¤������ ���src/Console/WarningsDetector.phpF��è‰mhF��º“‰¤������*���src/Console/Output/Progress/DotsOutput.php¤ ��è‰mh¤ ��¦8z¤������7���src/Console/Output/Progress/ProgressOutputInterface.php��è‰mh��ËÔŒ¤������2���src/Console/Output/Progress/ProgressOutputType.php-��è‰mh-��”¾/¤������3���src/Console/Output/Progress/PercentageBarOutput.php��è‰mh���7Ф������5���src/Console/Output/Progress/ProgressOutputFactory.php±��è‰mh±��“Ï«ç¤������*���src/Console/Output/Progress/NullOutput.phpC��è‰mhC��6¤A%¤������"���src/Console/Output/ErrorOutput.phpî ��è‰mhî ��Ú=v ¤������$���src/Console/Output/OutputContext.phpª��è‰mhª��“øtR¤������%���src/Console/ConfigurationResolver.php=R��è‰mh=R��̵ ¤������3���src/Console/Report/ListSetsReport/ReportSummary.phpc��è‰mhc��ôͶf¤������2���src/Console/Report/ListSetsReport/TextReporter.php���è‰mh���ú«€j¤������2���src/Console/Report/ListSetsReport/JsonReporter.php��è‰mh��t2ޤ������5���src/Console/Report/ListSetsReport/ReporterFactory.php£��è‰mh£�� 2æ[¤������7���src/Console/Report/ListSetsReport/ReporterInterface.phpî���è‰mhî���ÙÛ|@¤������.���src/Console/Report/FixReport/JunitReporter.php­��è‰mh­��ÿC%|¤������,���src/Console/Report/FixReport/XmlReporter.phpX ��è‰mhX ��øÁÖ‡¤������.���src/Console/Report/FixReport/ReportSummary.php«��è‰mh«��ξv,¤������/���src/Console/Report/FixReport/GitlabReporter.php¢��è‰mh¢��ða(K¤������3���src/Console/Report/FixReport/CheckstyleReporter.php&��è‰mh&��F{%î¤������-���src/Console/Report/FixReport/TextReporter.php“��è‰mh“��¢×a ¤������-���src/Console/Report/FixReport/JsonReporter.php%��è‰mh%��>ÝÜn¤������0���src/Console/Report/FixReport/ReporterFactory.phpŸ��è‰mhŸ��V#ܤ������2���src/Console/Report/FixReport/ReporterInterface.phpé���è‰mhé���j¡E¤������5���src/Console/Command/DescribeNameNotFoundException.phpÊ��è‰mhÊ��9c¤������$���src/Console/Command/CheckCommand.phpê��è‰mhê��ÊÛ|k¤������#���src/Console/Command/HelpCommand.php^��è‰mh^��^M-o¤������6���src/Console/Command/FixCommandExitStatusCalculator.phpŽ��è‰mhŽ��*°¤������"���src/Console/Command/FixCommand.php¸@��è‰mh¸@��F^ïr¤������(���src/Console/Command/ListFilesCommand.php���è‰mh���]•¤������%���src/Console/Command/WorkerCommand.php¶��è‰mh¶���¼U¤������)���src/Console/Command/SelfUpdateCommand.phpX��è‰mhX��™‹ßÿ¤������,���src/Console/Command/DocumentationCommand.phpë
  196. ��è‰mhë
  197. ��Ç ¥±¤������'���src/Console/Command/ListSetsCommand.php��è‰mh��:õ�¤������'���src/Console/Command/DescribeCommand.php0��è‰mh0��Ù¯«Õ¤���������src/FileRemoval.php‚��è‰mh‚��$#Ò¤���������src/PharCheckerInterface.php©���è‰mh©���mÜ*¤������<?php
  198. declare(strict_types=1);
  199. /*
  200. * This file is part of PHP CS Fixer.
  201. *
  202. * (c) Fabien Potencier <fabien@symfony.com>
  203. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  204. *
  205. * This source file is subject to the MIT license that is bundled
  206. * with this source code in the file LICENSE.
  207. */
  208. use Composer\XdebugHandler\XdebugHandler;
  209. use PhpCsFixer\Console\Application;
  210. error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
  211. set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
  212. if (0 !== ($severity & error_reporting())) {
  213. throw new ErrorException($message, 0, $severity, $file, $line);
  214. }
  215. return true;
  216. });
  217. // check environment requirements
  218. (static function (): void {
  219. if (\PHP_VERSION_ID === (int) '80000') { // TODO use 8_00_00 once only PHP 7.4+ is supported by this entry file
  220. fwrite(STDERR, "PHP CS Fixer is not able run on PHP 8.0.0 due to bug in PHP tokenizer (https://bugs.php.net/bug.php?id=80462).\n");
  221. fwrite(STDERR, "Update PHP version to unblock execution.\n");
  222. exit(1);
  223. }
  224. if (\PHP_VERSION_ID < (int) '70400') {
  225. fwrite(STDERR, "PHP needs to be a minimum version of PHP 7.4.0.\n");
  226. fwrite(STDERR, 'Current PHP version: '.PHP_VERSION.".\n");
  227. exit(1);
  228. }
  229. // @TODO 4.0 cleanup
  230. if (false !== getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  231. fwrite(STDERR, "Setting PHP_CS_FIXER_IGNORE_ENV environment variable is deprecated and will be removed in 4.0, use unsupportedPhpVersionAllowed config instead.\n");
  232. }
  233. foreach (['json', 'tokenizer'] as $extension) {
  234. if (!extension_loaded($extension)) {
  235. fwrite(STDERR, sprintf("PHP extension ext-%s is missing from your system. Install or enable it.\n", $extension));
  236. if (filter_var(getenv('PHP_CS_FIXER_IGNORE_ENV'), FILTER_VALIDATE_BOOLEAN)) {
  237. fwrite(STDERR, "Ignoring environment requirements because `PHP_CS_FIXER_IGNORE_ENV` is set. Execution may be unstable.\n");
  238. } else {
  239. exit(1);
  240. }
  241. }
  242. }
  243. })();
  244. // load dependencies
  245. (static function (): void {
  246. $require = true;
  247. if (class_exists('Phar')) {
  248. // Maybe this file is used as phar-stub? Let's try!
  249. try {
  250. Phar::mapPhar('php-cs-fixer.phar');
  251. /** @phpstan-ignore requireOnce.fileNotFound */
  252. require_once 'phar://php-cs-fixer.phar/vendor/autoload.php';
  253. $require = false;
  254. } catch (PharException $e) {
  255. }
  256. }
  257. if ($require) {
  258. // OK, it's not, let give Composer autoloader a try!
  259. $possibleFiles = [__DIR__.'/../../autoload.php', __DIR__.'/../autoload.php', __DIR__.'/vendor/autoload.php'];
  260. $file = null;
  261. foreach ($possibleFiles as $possibleFile) {
  262. if (file_exists($possibleFile)) {
  263. $file = $possibleFile;
  264. break;
  265. }
  266. }
  267. if (null === $file) {
  268. throw new RuntimeException('Unable to locate autoload.php file.');
  269. }
  270. require_once $file;
  271. }
  272. })();
  273. // Restart if xdebug is loaded, unless the environment variable PHP_CS_FIXER_ALLOW_XDEBUG is set.
  274. $xdebug = new XdebugHandler('PHP_CS_FIXER');
  275. $xdebug->check();
  276. unset($xdebug);
  277. $application = new Application();
  278. $application->run();
  279. __HALT_COMPILER();
  280. Copyright (c) 2012+ Fabien Potencier, Dariusz Rumiński
  281. Permission is hereby granted, free of charge, to any person obtaining a copy
  282. of this software and associated documentation files (the "Software"), to deal
  283. in the Software without restriction, including without limitation the rights
  284. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  285. copies of the Software, and to permit persons to whom the Software is furnished
  286. to do so, subject to the following conditions:
  287. The above copyright notice and this permission notice shall be included in all
  288. copies or substantial portions of the Software.
  289. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  290. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  291. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  292. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  293. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  294. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  295. THE SOFTWARE.
  296. #!/bin/sh
  297. set -eu
  298. IFS='
  299. '
  300. CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "${COMMIT_RANGE}")
  301. if ! echo "${CHANGED_FILES}" | grep -qE "^(\\.php-cs-fixer(\\.dist)?\\.php|composer\\.lock)$"; then EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "${CHANGED_FILES}"); else EXTRA_ARGS=''; fi
  302. vendor/bin/php-cs-fixer check --config=.php-cs-fixer.dist.php -v --show-progress=dots --stop-on-violation --using-cache=no ${EXTRA_ARGS}
  303. #!/usr/bin/env php
  304. <?php
  305. declare(strict_types=1);
  306. use Fidry\CpuCoreCounter\Diagnoser;
  307. use Fidry\CpuCoreCounter\Finder\FinderRegistry;
  308. require_once __DIR__.'/../vendor/autoload.php';
  309. echo 'Executing finders...'.PHP_EOL.PHP_EOL;
  310. echo Diagnoser::execute(FinderRegistry::getAllVariants()).PHP_EOL;
  311. #!/usr/bin/env php
  312. <?php
  313. declare(strict_types=1);
  314. use Fidry\CpuCoreCounter\CpuCoreCounter;
  315. use Fidry\CpuCoreCounter\Finder\FinderRegistry;
  316. require_once __DIR__.'/../vendor/autoload.php';
  317. $separator = str_repeat('–', 80);
  318. echo 'With all finders...'.PHP_EOL.PHP_EOL;
  319. echo (new CpuCoreCounter(FinderRegistry::getAllVariants()))->trace().PHP_EOL;
  320. echo $separator.PHP_EOL.PHP_EOL;
  321. echo 'Logical CPU cores finders...'.PHP_EOL.PHP_EOL;
  322. echo (new CpuCoreCounter(FinderRegistry::getDefaultLogicalFinders()))->trace().PHP_EOL;
  323. echo $separator.PHP_EOL.PHP_EOL;
  324. echo 'Physical CPU cores finders...'.PHP_EOL.PHP_EOL;
  325. echo (new CpuCoreCounter(FinderRegistry::getDefaultPhysicalFinders()))->trace().PHP_EOL;
  326. echo $separator.PHP_EOL.PHP_EOL;
  327. #!/usr/bin/env php
  328. <?php
  329. declare(strict_types=1);
  330. use Fidry\CpuCoreCounter\Diagnoser;
  331. use Fidry\CpuCoreCounter\Finder\FinderRegistry;
  332. require_once __DIR__.'/../vendor/autoload.php';
  333. echo 'Running diagnosis...'.PHP_EOL.PHP_EOL;
  334. echo Diagnoser::diagnose(FinderRegistry::getAllVariants()).PHP_EOL;
  335. echo 'Logical CPU cores finders...'.PHP_EOL.PHP_EOL;
  336. echo Diagnoser::diagnose(FinderRegistry::getDefaultLogicalFinders()).PHP_EOL;
  337. echo 'Physical CPU cores finders...'.PHP_EOL.PHP_EOL;
  338. echo Diagnoser::diagnose(FinderRegistry::getDefaultPhysicalFinders()).PHP_EOL;
  339. <?php
  340. declare(strict_types=1);
  341. namespace Fidry\CpuCoreCounter;
  342. use Fidry\CpuCoreCounter\Finder\CpuCoreFinder;
  343. use Fidry\CpuCoreCounter\Finder\EnvVariableFinder;
  344. use Fidry\CpuCoreCounter\Finder\FinderRegistry;
  345. use InvalidArgumentException;
  346. use function implode;
  347. use function max;
  348. use function sprintf;
  349. use function sys_getloadavg;
  350. use const PHP_EOL;
  351. final class CpuCoreCounter
  352. {
  353. private $finders;
  354. private $count;
  355. public function __construct(?array $finders = null)
  356. {
  357. $this->finders = $finders ?? FinderRegistry::getDefaultLogicalFinders();
  358. }
  359. public function getAvailableForParallelisation(
  360. int $reservedCpus = 0,
  361. ?int $countLimit = null,
  362. ?float $loadLimit = null,
  363. ?float $systemLoadAverage = 0.
  364. ): ParallelisationResult {
  365. self::checkCountLimit($countLimit);
  366. self::checkLoadLimit($loadLimit);
  367. self::checkSystemLoadAverage($systemLoadAverage);
  368. $totalCoreCount = $this->getCountWithFallback(1);
  369. $availableCores = max(1, $totalCoreCount - $reservedCpus);
  370. if (null !== $loadLimit) {
  371. $correctedSystemLoadAverage = null === $systemLoadAverage
  372. ? sys_getloadavg()[0] ?? 0.
  373. : $systemLoadAverage;
  374. $availableCores = max(
  375. 1,
  376. $loadLimit * ($availableCores - $correctedSystemLoadAverage)
  377. );
  378. }
  379. if (null === $countLimit) {
  380. $correctedCountLimit = self::getKubernetesLimit();
  381. } else {
  382. $correctedCountLimit = $countLimit > 0
  383. ? $countLimit
  384. : max(1, $totalCoreCount + $countLimit);
  385. }
  386. if (null !== $correctedCountLimit && $availableCores > $correctedCountLimit) {
  387. $availableCores = $correctedCountLimit;
  388. }
  389. return new ParallelisationResult(
  390. $reservedCpus,
  391. $countLimit,
  392. $loadLimit,
  393. $systemLoadAverage,
  394. $correctedCountLimit,
  395. $correctedSystemLoadAverage ?? $systemLoadAverage,
  396. $totalCoreCount,
  397. (int) $availableCores
  398. );
  399. }
  400. public function getCount(): int
  401. {
  402. if (null === $this->count) {
  403. $this->count = $this->findCount();
  404. }
  405. return $this->count;
  406. }
  407. public function getCountWithFallback(int $fallback): int
  408. {
  409. try {
  410. return $this->getCount();
  411. } catch (NumberOfCpuCoreNotFound $exception) {
  412. return $fallback;
  413. }
  414. }
  415. public function trace(): string
  416. {
  417. $output = [];
  418. foreach ($this->finders as $finder) {
  419. $output[] = sprintf(
  420. 'Executing the finder "%s":',
  421. $finder->toString()
  422. );
  423. $output[] = $finder->diagnose();
  424. $cores = $finder->find();
  425. if (null !== $cores) {
  426. $output[] = 'Result found: '.$cores;
  427. break;
  428. }
  429. $output[] = '–––';
  430. }
  431. return implode(PHP_EOL, $output);
  432. }
  433. private function findCount(): int
  434. {
  435. foreach ($this->finders as $finder) {
  436. $cores = $finder->find();
  437. if (null !== $cores) {
  438. return $cores;
  439. }
  440. }
  441. throw NumberOfCpuCoreNotFound::create();
  442. }
  443. public function getFinderAndCores(): array
  444. {
  445. foreach ($this->finders as $finder) {
  446. $cores = $finder->find();
  447. if (null !== $cores) {
  448. return [$finder, $cores];
  449. }
  450. }
  451. throw NumberOfCpuCoreNotFound::create();
  452. }
  453. public static function getKubernetesLimit(): ?int
  454. {
  455. $finder = new EnvVariableFinder('KUBERNETES_CPU_LIMIT');
  456. return $finder->find();
  457. }
  458. private static function checkCountLimit(?int $countLimit): void
  459. {
  460. if (0 === $countLimit) {
  461. throw new InvalidArgumentException(
  462. 'The count limit must be a non zero integer. Got "0".'
  463. );
  464. }
  465. }
  466. private static function checkLoadLimit(?float $loadLimit): void
  467. {
  468. if (null === $loadLimit) {
  469. return;
  470. }
  471. if ($loadLimit < 0. || $loadLimit > 1.) {
  472. throw new InvalidArgumentException(
  473. sprintf(
  474. 'The load limit must be in the range [0., 1.], got "%s".',
  475. $loadLimit
  476. )
  477. );
  478. }
  479. }
  480. private static function checkSystemLoadAverage(?float $systemLoadAverage): void
  481. {
  482. if (null !== $systemLoadAverage && $systemLoadAverage < 0.) {
  483. throw new InvalidArgumentException(
  484. sprintf(
  485. 'The system load average must be a positive float, got "%s".',
  486. $systemLoadAverage
  487. )
  488. );
  489. }
  490. }
  491. }
  492. <?php
  493. declare(strict_types=1);
  494. namespace Fidry\CpuCoreCounter;
  495. use Fidry\CpuCoreCounter\Finder\CpuCoreFinder;
  496. use function array_map;
  497. use function explode;
  498. use function implode;
  499. use function max;
  500. use function str_repeat;
  501. use const PHP_EOL;
  502. final class Diagnoser
  503. {
  504. public static function diagnose(array $finders): string
  505. {
  506. $diagnoses = array_map(
  507. static function (CpuCoreFinder $finder): string {
  508. return self::diagnoseFinder($finder);
  509. },
  510. $finders
  511. );
  512. return implode(PHP_EOL, $diagnoses);
  513. }
  514. public static function execute(array $finders): string
  515. {
  516. $diagnoses = array_map(
  517. static function (CpuCoreFinder $finder): string {
  518. $coresCount = $finder->find();
  519. return implode(
  520. '',
  521. [
  522. $finder->toString(),
  523. ': ',
  524. null === $coresCount ? 'NULL' : $coresCount,
  525. ]
  526. );
  527. },
  528. $finders
  529. );
  530. return implode(PHP_EOL, $diagnoses);
  531. }
  532. private static function diagnoseFinder(CpuCoreFinder $finder): string
  533. {
  534. $diagnosis = $finder->diagnose();
  535. $maxLineLength = max(
  536. array_map(
  537. 'strlen',
  538. explode(PHP_EOL, $diagnosis)
  539. )
  540. );
  541. $separator = str_repeat('-', $maxLineLength);
  542. return implode(
  543. '',
  544. [
  545. $finder->toString().':'.PHP_EOL,
  546. $separator.PHP_EOL,
  547. $diagnosis.PHP_EOL,
  548. $separator.PHP_EOL,
  549. ]
  550. );
  551. }
  552. private function __construct()
  553. {
  554. }
  555. }
  556. <?php
  557. declare(strict_types=1);
  558. namespace Fidry\CpuCoreCounter;
  559. /**
  560. @readonly
  561. */
  562. final class ParallelisationResult
  563. {
  564. public $passedReservedCpus;
  565. public $passedCountLimit;
  566. public $passedLoadLimit;
  567. public $passedSystemLoadAverage;
  568. public $correctedCountLimit;
  569. public $correctedSystemLoadAverage;
  570. public $totalCoresCount;
  571. public $availableCpus;
  572. public function __construct(
  573. int $passedReservedCpus,
  574. ?int $passedCountLimit,
  575. ?float $passedLoadLimit,
  576. ?float $passedSystemLoadAverage,
  577. ?int $correctedCountLimit,
  578. ?float $correctedSystemLoadAverage,
  579. int $totalCoresCount,
  580. int $availableCpus
  581. ) {
  582. $this->passedReservedCpus = $passedReservedCpus;
  583. $this->passedCountLimit = $passedCountLimit;
  584. $this->passedLoadLimit = $passedLoadLimit;
  585. $this->passedSystemLoadAverage = $passedSystemLoadAverage;
  586. $this->correctedCountLimit = $correctedCountLimit;
  587. $this->correctedSystemLoadAverage = $correctedSystemLoadAverage;
  588. $this->totalCoresCount = $totalCoresCount;
  589. $this->availableCpus = $availableCpus;
  590. }
  591. }
  592. <?php
  593. declare(strict_types=1);
  594. namespace Fidry\CpuCoreCounter;
  595. use RuntimeException;
  596. final class NumberOfCpuCoreNotFound extends RuntimeException
  597. {
  598. public static function create(): self
  599. {
  600. return new self(
  601. 'Could not find the number of CPU cores available.'
  602. );
  603. }
  604. }
  605. <?php
  606. declare(strict_types=1);
  607. namespace Fidry\CpuCoreCounter\Finder;
  608. use function count;
  609. use function explode;
  610. use function is_array;
  611. use function preg_grep;
  612. use function strtok;
  613. use const PHP_EOL;
  614. final class LscpuPhysicalFinder extends ProcOpenBasedFinder
  615. {
  616. public function toString(): string
  617. {
  618. return 'LscpuPhysicalFinder';
  619. }
  620. public function getCommand(): string
  621. {
  622. return 'lscpu -p';
  623. }
  624. protected function countCpuCores(string $process): ?int
  625. {
  626. $lines = explode(PHP_EOL, $process);
  627. $actualLines = preg_grep('/^\d+/', $lines);
  628. if (!is_array($actualLines)) {
  629. return null;
  630. }
  631. $cores = [];
  632. foreach ($actualLines as $line) {
  633. strtok($line, ',');
  634. $core = strtok(',');
  635. if (false === $core) {
  636. continue;
  637. }
  638. $cores[$core] = true;
  639. }
  640. unset($cores['-']);
  641. $count = count($cores);
  642. return 0 === $count ? null : $count;
  643. }
  644. }
  645. <?php
  646. declare(strict_types=1);
  647. namespace Fidry\CpuCoreCounter\Finder;
  648. use function preg_match;
  649. final class CmiCmdletLogicalFinder extends ProcOpenBasedFinder
  650. {
  651. private const CPU_CORE_COUNT_REGEX = '/NumberOfLogicalProcessors[\s\n]-+[\s\n]+(?<count>\d+)/';
  652. protected function getCommand(): string
  653. {
  654. return 'Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property NumberOfLogicalProcessors';
  655. }
  656. public function toString(): string
  657. {
  658. return 'CmiCmdletLogicalFinder';
  659. }
  660. protected function countCpuCores(string $process): ?int
  661. {
  662. if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) {
  663. return parent::countCpuCores($process);
  664. }
  665. $count = $matches['count'];
  666. return parent::countCpuCores($count);
  667. }
  668. }
  669. <?php
  670. declare(strict_types=1);
  671. namespace Fidry\CpuCoreCounter\Finder;
  672. use function preg_match;
  673. final class WmicLogicalFinder extends ProcOpenBasedFinder
  674. {
  675. private const CPU_CORE_COUNT_REGEX = '/NumberOfLogicalProcessors[\s\n]+(?<count>\d+)/';
  676. protected function getCommand(): string
  677. {
  678. return 'wmic cpu get NumberOfLogicalProcessors';
  679. }
  680. public function toString(): string
  681. {
  682. return 'WmicLogicalFinder';
  683. }
  684. protected function countCpuCores(string $process): ?int
  685. {
  686. if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) {
  687. return parent::countCpuCores($process);
  688. }
  689. $count = $matches['count'];
  690. return parent::countCpuCores($count);
  691. }
  692. }
  693. <?php
  694. declare(strict_types=1);
  695. namespace Fidry\CpuCoreCounter\Finder;
  696. use function sprintf;
  697. final class DummyCpuCoreFinder implements CpuCoreFinder
  698. {
  699. private $count;
  700. public function diagnose(): string
  701. {
  702. return sprintf(
  703. 'Will return "%d".',
  704. $this->count
  705. );
  706. }
  707. public function __construct(int $count)
  708. {
  709. $this->count = $count;
  710. }
  711. public function find(): ?int
  712. {
  713. return $this->count;
  714. }
  715. public function toString(): string
  716. {
  717. return sprintf(
  718. 'DummyCpuCoreFinder(value=%d)',
  719. $this->count
  720. );
  721. }
  722. }
  723. <?php
  724. declare(strict_types=1);
  725. namespace Fidry\CpuCoreCounter\Finder;
  726. interface CpuCoreFinder
  727. {
  728. public function diagnose(): string;
  729. public function find(): ?int;
  730. public function toString(): string;
  731. }
  732. <?php
  733. declare(strict_types=1);
  734. namespace Fidry\CpuCoreCounter\Finder;
  735. use Fidry\CpuCoreCounter\Executor\ProcessExecutor;
  736. use function sprintf;
  737. final class NProcFinder extends ProcOpenBasedFinder
  738. {
  739. private $all;
  740. public function __construct(
  741. bool $all = false,
  742. ?ProcessExecutor $executor = null
  743. ) {
  744. parent::__construct($executor);
  745. $this->all = $all;
  746. }
  747. public function toString(): string
  748. {
  749. return sprintf(
  750. 'NProcFinder(all=%s)',
  751. $this->all ? 'true' : 'false'
  752. );
  753. }
  754. protected function getCommand(): string
  755. {
  756. return 'nproc'.($this->all ? ' --all' : '');
  757. }
  758. }
  759. <?php
  760. declare(strict_types=1);
  761. namespace Fidry\CpuCoreCounter\Finder;
  762. use function array_filter;
  763. use function count;
  764. use function explode;
  765. use const PHP_EOL;
  766. final class WindowsRegistryLogicalFinder extends ProcOpenBasedFinder
  767. {
  768. protected function getCommand(): string
  769. {
  770. return 'reg query HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor';
  771. }
  772. public function toString(): string
  773. {
  774. return 'WindowsRegistryLogicalFinder';
  775. }
  776. protected function countCpuCores(string $process): ?int
  777. {
  778. $count = count(
  779. array_filter(
  780. explode(PHP_EOL, $process),
  781. static function (string $line): bool {
  782. return '' !== trim($line);
  783. }
  784. )
  785. );
  786. return $count > 0 ? $count : null;
  787. }
  788. }
  789. <?php
  790. declare(strict_types=1);
  791. namespace Fidry\CpuCoreCounter\Finder;
  792. use function count;
  793. use function explode;
  794. use function is_array;
  795. use function preg_grep;
  796. use const PHP_EOL;
  797. final class LscpuLogicalFinder extends ProcOpenBasedFinder
  798. {
  799. public function getCommand(): string
  800. {
  801. return 'lscpu -p';
  802. }
  803. protected function countCpuCores(string $process): ?int
  804. {
  805. $lines = explode(PHP_EOL, $process);
  806. $actualLines = preg_grep('/^\d+,/', $lines);
  807. if (!is_array($actualLines)) {
  808. return null;
  809. }
  810. $count = count($actualLines);
  811. return 0 === $count ? null : $count;
  812. }
  813. public function toString(): string
  814. {
  815. return 'LscpuLogicalFinder';
  816. }
  817. }
  818. <?php
  819. declare(strict_types=1);
  820. namespace Fidry\CpuCoreCounter\Finder;
  821. final class HwLogicalFinder extends ProcOpenBasedFinder
  822. {
  823. protected function getCommand(): string
  824. {
  825. return 'sysctl -n hw.logicalcpu';
  826. }
  827. public function toString(): string
  828. {
  829. return 'HwLogicalFinder';
  830. }
  831. }
  832. <?php
  833. declare(strict_types=1);
  834. namespace Fidry\CpuCoreCounter\Finder;
  835. final class NProcessorFinder extends ProcOpenBasedFinder
  836. {
  837. protected function getCommand(): string
  838. {
  839. return 'getconf NPROCESSORS_ONLN';
  840. }
  841. public function toString(): string
  842. {
  843. return 'NProcessorFinder';
  844. }
  845. }
  846. <?php
  847. declare(strict_types=1);
  848. namespace Fidry\CpuCoreCounter\Finder;
  849. final class FinderRegistry
  850. {
  851. public static function getAllVariants(): array
  852. {
  853. return [
  854. new CpuInfoFinder(),
  855. new DummyCpuCoreFinder(1),
  856. new HwLogicalFinder(),
  857. new HwPhysicalFinder(),
  858. new LscpuLogicalFinder(),
  859. new LscpuPhysicalFinder(),
  860. new _NProcessorFinder(),
  861. new NProcessorFinder(),
  862. new NProcFinder(true),
  863. new NProcFinder(false),
  864. new NullCpuCoreFinder(),
  865. SkipOnOSFamilyFinder::forWindows(
  866. new DummyCpuCoreFinder(1)
  867. ),
  868. OnlyOnOSFamilyFinder::forWindows(
  869. new DummyCpuCoreFinder(1)
  870. ),
  871. new OnlyInPowerShellFinder(new CmiCmdletLogicalFinder()),
  872. new OnlyInPowerShellFinder(new CmiCmdletPhysicalFinder()),
  873. new WindowsRegistryLogicalFinder(),
  874. new WmicPhysicalFinder(),
  875. new WmicLogicalFinder(),
  876. ];
  877. }
  878. public static function getDefaultLogicalFinders(): array
  879. {
  880. return [
  881. OnlyOnOSFamilyFinder::forWindows(
  882. new OnlyInPowerShellFinder(
  883. new CmiCmdletLogicalFinder()
  884. )
  885. ),
  886. OnlyOnOSFamilyFinder::forWindows(new WindowsRegistryLogicalFinder()),
  887. OnlyOnOSFamilyFinder::forWindows(new WmicLogicalFinder()),
  888. new NProcFinder(),
  889. new HwLogicalFinder(),
  890. new _NProcessorFinder(),
  891. new NProcessorFinder(),
  892. new LscpuLogicalFinder(),
  893. new CpuInfoFinder(),
  894. ];
  895. }
  896. public static function getDefaultPhysicalFinders(): array
  897. {
  898. return [
  899. OnlyOnOSFamilyFinder::forWindows(
  900. new OnlyInPowerShellFinder(
  901. new CmiCmdletPhysicalFinder()
  902. )
  903. ),
  904. OnlyOnOSFamilyFinder::forWindows(new WmicPhysicalFinder()),
  905. new HwPhysicalFinder(),
  906. new LscpuPhysicalFinder(),
  907. ];
  908. }
  909. private function __construct()
  910. {
  911. }
  912. }
  913. <?php
  914. declare(strict_types=1);
  915. namespace Fidry\CpuCoreCounter\Finder;
  916. final class HwPhysicalFinder extends ProcOpenBasedFinder
  917. {
  918. protected function getCommand(): string
  919. {
  920. return 'sysctl -n hw.physicalcpu';
  921. }
  922. public function toString(): string
  923. {
  924. return 'HwPhysicalFinder';
  925. }
  926. }
  927. <?php
  928. declare(strict_types=1);
  929. namespace Fidry\CpuCoreCounter\Finder;
  930. final class _NProcessorFinder extends ProcOpenBasedFinder
  931. {
  932. protected function getCommand(): string
  933. {
  934. return 'getconf _NPROCESSORS_ONLN';
  935. }
  936. public function toString(): string
  937. {
  938. return '_NProcessorFinder';
  939. }
  940. }
  941. <?php
  942. declare(strict_types=1);
  943. namespace Fidry\CpuCoreCounter\Finder;
  944. use function implode;
  945. use function in_array;
  946. use function sprintf;
  947. final class SkipOnOSFamilyFinder implements CpuCoreFinder
  948. {
  949. private $skippedOSFamilies;
  950. private $decoratedFinder;
  951. public function __construct(
  952. $skippedOSFamilyOrFamilies,
  953. CpuCoreFinder $decoratedFinder
  954. ) {
  955. $this->skippedOSFamilies = (array) $skippedOSFamilyOrFamilies;
  956. $this->decoratedFinder = $decoratedFinder;
  957. }
  958. public static function forWindows(CpuCoreFinder $decoratedFinder): self
  959. {
  960. return new self(
  961. 'Windows',
  962. $decoratedFinder
  963. );
  964. }
  965. public static function forBSD(CpuCoreFinder $decoratedFinder): self
  966. {
  967. return new self(
  968. 'BSD',
  969. $decoratedFinder
  970. );
  971. }
  972. public static function forDarwin(CpuCoreFinder $decoratedFinder): self
  973. {
  974. return new self(
  975. 'Darwin',
  976. $decoratedFinder
  977. );
  978. }
  979. public static function forSolaris(CpuCoreFinder $decoratedFinder): self
  980. {
  981. return new self(
  982. 'Solaris',
  983. $decoratedFinder
  984. );
  985. }
  986. public static function forLinux(CpuCoreFinder $decoratedFinder): self
  987. {
  988. return new self(
  989. 'Linux',
  990. $decoratedFinder
  991. );
  992. }
  993. public function diagnose(): string
  994. {
  995. return $this->skip()
  996. ? sprintf(
  997. 'Skipped platform detected ("%s").',
  998. PHP_OS_FAMILY
  999. )
  1000. : $this->decoratedFinder->diagnose();
  1001. }
  1002. public function find(): ?int
  1003. {
  1004. return $this->skip()
  1005. ? null
  1006. : $this->decoratedFinder->find();
  1007. }
  1008. public function toString(): string
  1009. {
  1010. return sprintf(
  1011. 'SkipOnOSFamilyFinder(skip=(%s),%s)',
  1012. implode(',', $this->skippedOSFamilies),
  1013. $this->decoratedFinder->toString()
  1014. );
  1015. }
  1016. private function skip(): bool
  1017. {
  1018. return in_array(PHP_OS_FAMILY, $this->skippedOSFamilies, true);
  1019. }
  1020. }
  1021. <?php
  1022. declare(strict_types=1);
  1023. namespace Fidry\CpuCoreCounter\Finder;
  1024. use function getenv;
  1025. use function sprintf;
  1026. final class OnlyInPowerShellFinder implements CpuCoreFinder
  1027. {
  1028. private $decoratedFinder;
  1029. public function __construct(CpuCoreFinder $decoratedFinder)
  1030. {
  1031. $this->decoratedFinder = $decoratedFinder;
  1032. }
  1033. public function diagnose(): string
  1034. {
  1035. $powerShellModulePath = getenv('PSModulePath');
  1036. return $this->skip()
  1037. ? sprintf(
  1038. 'Skipped; no power shell module path detected ("%s").',
  1039. $powerShellModulePath
  1040. )
  1041. : $this->decoratedFinder->diagnose();
  1042. }
  1043. public function find(): ?int
  1044. {
  1045. return $this->skip()
  1046. ? null
  1047. : $this->decoratedFinder->find();
  1048. }
  1049. public function toString(): string
  1050. {
  1051. return sprintf(
  1052. 'OnlyInPowerShellFinder(%s)',
  1053. $this->decoratedFinder->toString()
  1054. );
  1055. }
  1056. private function skip(): bool
  1057. {
  1058. return false === getenv('PSModulePath');
  1059. }
  1060. }
  1061. <?php
  1062. declare(strict_types=1);
  1063. namespace Fidry\CpuCoreCounter\Finder;
  1064. use Fidry\CpuCoreCounter\Executor\ProcessExecutor;
  1065. use Fidry\CpuCoreCounter\Executor\ProcOpenExecutor;
  1066. use function filter_var;
  1067. use function function_exists;
  1068. use function is_int;
  1069. use function sprintf;
  1070. use function trim;
  1071. use const FILTER_VALIDATE_INT;
  1072. use const PHP_EOL;
  1073. abstract class ProcOpenBasedFinder implements CpuCoreFinder
  1074. {
  1075. private $executor;
  1076. public function __construct(?ProcessExecutor $executor = null)
  1077. {
  1078. $this->executor = $executor ?? new ProcOpenExecutor();
  1079. }
  1080. public function diagnose(): string
  1081. {
  1082. if (!function_exists('proc_open')) {
  1083. return 'The function "proc_open" is not available.';
  1084. }
  1085. $command = $this->getCommand();
  1086. $output = $this->executor->execute($command);
  1087. if (null === $output) {
  1088. return sprintf(
  1089. 'Failed to execute the command "%s".',
  1090. $command
  1091. );
  1092. }
  1093. [$stdout, $stderr] = $output;
  1094. $failed = '' !== trim($stderr);
  1095. return $failed
  1096. ? sprintf(
  1097. 'Executed the command "%s" which wrote the following output to the STDERR:%s%s%sWill return "null".',
  1098. $command,
  1099. PHP_EOL,
  1100. $stderr,
  1101. PHP_EOL
  1102. )
  1103. : sprintf(
  1104. 'Executed the command "%s" and got the following (STDOUT) output:%s%s%sWill return "%s".',
  1105. $command,
  1106. PHP_EOL,
  1107. $stdout,
  1108. PHP_EOL,
  1109. $this->countCpuCores($stdout) ?? 'null'
  1110. );
  1111. }
  1112. public function find(): ?int
  1113. {
  1114. $output = $this->executor->execute($this->getCommand());
  1115. if (null === $output) {
  1116. return null;
  1117. }
  1118. [$stdout, $stderr] = $output;
  1119. $failed = '' !== trim($stderr);
  1120. return $failed
  1121. ? null
  1122. : $this->countCpuCores($stdout);
  1123. }
  1124. protected function countCpuCores(string $process): ?int
  1125. {
  1126. $cpuCount = filter_var($process, FILTER_VALIDATE_INT);
  1127. return is_int($cpuCount) && $cpuCount > 0 ? $cpuCount : null;
  1128. }
  1129. abstract protected function getCommand(): string;
  1130. }
  1131. <?php
  1132. declare(strict_types=1);
  1133. namespace Fidry\CpuCoreCounter\Finder;
  1134. use function preg_match;
  1135. final class CmiCmdletPhysicalFinder extends ProcOpenBasedFinder
  1136. {
  1137. private const CPU_CORE_COUNT_REGEX = '/NumberOfCores[\s\n]-+[\s\n]+(?<count>\d+)/';
  1138. protected function getCommand(): string
  1139. {
  1140. return 'Get-CimInstance -ClassName Win32_Processor | Select-Object -Property NumberOfCores';
  1141. }
  1142. public function toString(): string
  1143. {
  1144. return 'CmiCmdletPhysicalFinder';
  1145. }
  1146. protected function countCpuCores(string $process): ?int
  1147. {
  1148. if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) {
  1149. return parent::countCpuCores($process);
  1150. }
  1151. $count = $matches['count'];
  1152. return parent::countCpuCores($count);
  1153. }
  1154. }
  1155. <?php
  1156. declare(strict_types=1);
  1157. namespace Fidry\CpuCoreCounter\Finder;
  1158. use function getenv;
  1159. use function preg_match;
  1160. use function sprintf;
  1161. use function var_export;
  1162. final class EnvVariableFinder implements CpuCoreFinder
  1163. {
  1164. private $environmentVariableName;
  1165. public function __construct(string $environmentVariableName)
  1166. {
  1167. $this->environmentVariableName = $environmentVariableName;
  1168. }
  1169. public function diagnose(): string
  1170. {
  1171. $value = getenv($this->environmentVariableName);
  1172. return sprintf(
  1173. 'parse(getenv(%s)=%s)=%s',
  1174. $this->environmentVariableName,
  1175. var_export($value, true),
  1176. self::isPositiveInteger($value) ? $value : 'null'
  1177. );
  1178. }
  1179. public function find(): ?int
  1180. {
  1181. $value = getenv($this->environmentVariableName);
  1182. return self::isPositiveInteger($value)
  1183. ? (int) $value
  1184. : null;
  1185. }
  1186. public function toString(): string
  1187. {
  1188. return sprintf(
  1189. 'getenv(%s)',
  1190. $this->environmentVariableName
  1191. );
  1192. }
  1193. private static function isPositiveInteger($value): bool
  1194. {
  1195. return false !== $value
  1196. && 1 === preg_match('/^\d+$/', $value)
  1197. && (int) $value > 0;
  1198. }
  1199. }
  1200. <?php
  1201. declare(strict_types=1);
  1202. namespace Fidry\CpuCoreCounter\Finder;
  1203. use function implode;
  1204. use function sprintf;
  1205. use const PHP_OS_FAMILY;
  1206. final class OnlyOnOSFamilyFinder implements CpuCoreFinder
  1207. {
  1208. private $skippedOSFamilies;
  1209. private $decoratedFinder;
  1210. public function __construct(
  1211. $skippedOSFamilyOrFamilies,
  1212. CpuCoreFinder $decoratedFinder
  1213. ) {
  1214. $this->skippedOSFamilies = (array) $skippedOSFamilyOrFamilies;
  1215. $this->decoratedFinder = $decoratedFinder;
  1216. }
  1217. public static function forWindows(CpuCoreFinder $decoratedFinder): self
  1218. {
  1219. return new self(
  1220. 'Windows',
  1221. $decoratedFinder
  1222. );
  1223. }
  1224. public static function forBSD(CpuCoreFinder $decoratedFinder): self
  1225. {
  1226. return new self(
  1227. 'BSD',
  1228. $decoratedFinder
  1229. );
  1230. }
  1231. public static function forDarwin(CpuCoreFinder $decoratedFinder): self
  1232. {
  1233. return new self(
  1234. 'Darwin',
  1235. $decoratedFinder
  1236. );
  1237. }
  1238. public static function forSolaris(CpuCoreFinder $decoratedFinder): self
  1239. {
  1240. return new self(
  1241. 'Solaris',
  1242. $decoratedFinder
  1243. );
  1244. }
  1245. public static function forLinux(CpuCoreFinder $decoratedFinder): self
  1246. {
  1247. return new self(
  1248. 'Linux',
  1249. $decoratedFinder
  1250. );
  1251. }
  1252. public function diagnose(): string
  1253. {
  1254. return $this->skip()
  1255. ? sprintf(
  1256. 'Skipped platform detected ("%s").',
  1257. PHP_OS_FAMILY
  1258. )
  1259. : $this->decoratedFinder->diagnose();
  1260. }
  1261. public function find(): ?int
  1262. {
  1263. return $this->skip()
  1264. ? null
  1265. : $this->decoratedFinder->find();
  1266. }
  1267. public function toString(): string
  1268. {
  1269. return sprintf(
  1270. 'OnlyOnOSFamilyFinder(only=(%s),%s)',
  1271. implode(',', $this->skippedOSFamilies),
  1272. $this->decoratedFinder->toString()
  1273. );
  1274. }
  1275. private function skip(): bool
  1276. {
  1277. return !in_array(PHP_OS_FAMILY, $this->skippedOSFamilies, true);
  1278. }
  1279. }
  1280. <?php
  1281. declare(strict_types=1);
  1282. namespace Fidry\CpuCoreCounter\Finder;
  1283. use function preg_match;
  1284. final class WmicPhysicalFinder extends ProcOpenBasedFinder
  1285. {
  1286. private const CPU_CORE_COUNT_REGEX = '/NumberOfCores[\s\n]+(?<count>\d+)/';
  1287. protected function getCommand(): string
  1288. {
  1289. return 'wmic cpu get NumberOfCores';
  1290. }
  1291. public function toString(): string
  1292. {
  1293. return 'WmicPhysicalFinder';
  1294. }
  1295. protected function countCpuCores(string $process): ?int
  1296. {
  1297. if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) {
  1298. return parent::countCpuCores($process);
  1299. }
  1300. $count = $matches['count'];
  1301. return parent::countCpuCores($count);
  1302. }
  1303. }
  1304. <?php
  1305. declare(strict_types=1);
  1306. namespace Fidry\CpuCoreCounter\Finder;
  1307. final class NullCpuCoreFinder implements CpuCoreFinder
  1308. {
  1309. public function diagnose(): string
  1310. {
  1311. return 'Will return "null".';
  1312. }
  1313. public function find(): ?int
  1314. {
  1315. return null;
  1316. }
  1317. public function toString(): string
  1318. {
  1319. return 'NullCpuCoreFinder';
  1320. }
  1321. }
  1322. <?php
  1323. declare(strict_types=1);
  1324. namespace Fidry\CpuCoreCounter\Finder;
  1325. use function file_get_contents;
  1326. use function is_file;
  1327. use function sprintf;
  1328. use function substr_count;
  1329. use const PHP_EOL;
  1330. final class CpuInfoFinder implements CpuCoreFinder
  1331. {
  1332. private const CPU_INFO_PATH = '/proc/cpuinfo';
  1333. public function diagnose(): string
  1334. {
  1335. if (!is_file(self::CPU_INFO_PATH)) {
  1336. return sprintf(
  1337. 'The file "%s" could not be found.',
  1338. self::CPU_INFO_PATH
  1339. );
  1340. }
  1341. $cpuInfo = file_get_contents(self::CPU_INFO_PATH);
  1342. if (false === $cpuInfo) {
  1343. return sprintf(
  1344. 'Could not get the content of the file "%s".',
  1345. self::CPU_INFO_PATH
  1346. );
  1347. }
  1348. return sprintf(
  1349. 'Found the file "%s" with the content:%s%s%sWill return "%s".',
  1350. self::CPU_INFO_PATH,
  1351. PHP_EOL,
  1352. $cpuInfo,
  1353. PHP_EOL,
  1354. self::countCpuCores($cpuInfo)
  1355. );
  1356. }
  1357. public function find(): ?int
  1358. {
  1359. $cpuInfo = self::getCpuInfo();
  1360. return null === $cpuInfo ? null : self::countCpuCores($cpuInfo);
  1361. }
  1362. public function toString(): string
  1363. {
  1364. return 'CpuInfoFinder';
  1365. }
  1366. private static function getCpuInfo(): ?string
  1367. {
  1368. if (!@is_file(self::CPU_INFO_PATH)) {
  1369. return null;
  1370. }
  1371. $cpuInfo = @file_get_contents(self::CPU_INFO_PATH);
  1372. return false === $cpuInfo
  1373. ? null
  1374. : $cpuInfo;
  1375. }
  1376. public static function countCpuCores(string $cpuInfo): ?int
  1377. {
  1378. $processorCount = substr_count($cpuInfo, 'processor');
  1379. return $processorCount > 0 ? $processorCount : null;
  1380. }
  1381. }
  1382. <?php
  1383. declare(strict_types=1);
  1384. namespace Fidry\CpuCoreCounter\Executor;
  1385. interface ProcessExecutor
  1386. {
  1387. public function execute(string $command): ?array;
  1388. }
  1389. <?php
  1390. declare(strict_types=1);
  1391. namespace Fidry\CpuCoreCounter\Executor;
  1392. use function fclose;
  1393. use function function_exists;
  1394. use function is_resource;
  1395. use function proc_close;
  1396. use function proc_open;
  1397. use function stream_get_contents;
  1398. final class ProcOpenExecutor implements ProcessExecutor
  1399. {
  1400. public function execute(string $command): ?array
  1401. {
  1402. if (!function_exists('proc_open')) {
  1403. return null;
  1404. }
  1405. $pipes = [];
  1406. $process = @proc_open(
  1407. $command,
  1408. [
  1409. ['pipe', 'rb'],
  1410. ['pipe', 'wb'],
  1411. ['pipe', 'wb'],
  1412. ],
  1413. $pipes
  1414. );
  1415. if (!is_resource($process)) {
  1416. return null;
  1417. }
  1418. fclose($pipes[0]);
  1419. $stdout = (string) stream_get_contents($pipes[1]);
  1420. $stderr = (string) stream_get_contents($pipes[2]);
  1421. proc_close($process);
  1422. return [$stdout, $stderr];
  1423. }
  1424. }
  1425. <?php
  1426. namespace Clue\React\NDJson;
  1427. use Evenement\EventEmitter;
  1428. use React\Stream\WritableStreamInterface;
  1429. class Encoder extends EventEmitter implements WritableStreamInterface
  1430. {
  1431. private $output;
  1432. private $options;
  1433. private $depth;
  1434. private $closed = false;
  1435. public function __construct(WritableStreamInterface $output, $options = 0, $depth = 512)
  1436. {
  1437. if (\defined('JSON_PRETTY_PRINT') && $options & \JSON_PRETTY_PRINT) {
  1438. throw new \InvalidArgumentException('Pretty printing not available for NDJSON');
  1439. }
  1440. if ($depth !== 512 && \PHP_VERSION < 5.5) {
  1441. throw new \BadMethodCallException('Depth parameter is only supported on PHP 5.5+');
  1442. }
  1443. if (\defined('JSON_THROW_ON_ERROR')) {
  1444. $options = $options & ~\JSON_THROW_ON_ERROR;
  1445. }
  1446. $this->output = $output;
  1447. if (!$output->isWritable()) {
  1448. $this->close();
  1449. return;
  1450. }
  1451. $this->options = $options;
  1452. $this->depth = $depth;
  1453. $this->output->on('drain', array($this, 'handleDrain'));
  1454. $this->output->on('error', array($this, 'handleError'));
  1455. $this->output->on('close', array($this, 'close'));
  1456. }
  1457. public function write($data)
  1458. {
  1459. if ($this->closed) {
  1460. return false;
  1461. }
  1462. if (\PHP_VERSION_ID < 50500) {
  1463. $errstr = null;
  1464. \set_error_handler(function ($_, $error) use (&$errstr) {
  1465. $errstr = $error;
  1466. });
  1467. $data = \json_encode($data, $this->options);
  1468. \restore_error_handler();
  1469. $errno = \json_last_error();
  1470. if (\defined('JSON_ERROR_UTF8') && $errno === \JSON_ERROR_UTF8) {
  1471. $errstr = 'Malformed UTF-8 characters, possibly incorrectly encoded';
  1472. } elseif ($errno !== \JSON_ERROR_NONE && $errstr === null) {
  1473. $errstr = 'Unknown error';
  1474. }
  1475. if ($errno !== \JSON_ERROR_NONE || $errstr !== null) {
  1476. $this->handleError(new \RuntimeException('Unable to encode JSON: ' . $errstr, $errno));
  1477. return false;
  1478. }
  1479. } else {
  1480. $data = \json_encode($data, $this->options, $this->depth);
  1481. if ($data === false && \json_last_error() !== \JSON_ERROR_NONE) {
  1482. $this->handleError(new \RuntimeException('Unable to encode JSON: ' . \json_last_error_msg(), \json_last_error()));
  1483. return false;
  1484. }
  1485. }
  1486. return $this->output->write($data . "\n");
  1487. }
  1488. public function end($data = null)
  1489. {
  1490. if ($data !== null) {
  1491. $this->write($data);
  1492. }
  1493. $this->output->end();
  1494. }
  1495. public function isWritable()
  1496. {
  1497. return !$this->closed;
  1498. }
  1499. public function close()
  1500. {
  1501. if ($this->closed) {
  1502. return;
  1503. }
  1504. $this->closed = true;
  1505. $this->output->close();
  1506. $this->emit('close');
  1507. $this->removeAllListeners();
  1508. }
  1509. public function handleDrain()
  1510. {
  1511. $this->emit('drain');
  1512. }
  1513. public function handleError(\Exception $error)
  1514. {
  1515. $this->emit('error', array($error));
  1516. $this->close();
  1517. }
  1518. }
  1519. <?php
  1520. namespace Clue\React\NDJson;
  1521. use Evenement\EventEmitter;
  1522. use React\Stream\ReadableStreamInterface;
  1523. use React\Stream\Util;
  1524. use React\Stream\WritableStreamInterface;
  1525. class Decoder extends EventEmitter implements ReadableStreamInterface
  1526. {
  1527. private $input;
  1528. private $assoc;
  1529. private $depth;
  1530. private $options;
  1531. private $maxlength;
  1532. private $buffer = '';
  1533. private $closed = false;
  1534. public function __construct(ReadableStreamInterface $input, $assoc = false, $depth = 512, $options = 0, $maxlength = 65536)
  1535. {
  1536. if ($options !== 0 && \PHP_VERSION < 5.4) {
  1537. throw new \BadMethodCallException('Options parameter is only supported on PHP 5.4+');
  1538. }
  1539. if (\defined('JSON_THROW_ON_ERROR')) {
  1540. $options = $options & ~\JSON_THROW_ON_ERROR;
  1541. }
  1542. $this->input = $input;
  1543. if (!$input->isReadable()) {
  1544. $this->close();
  1545. return;
  1546. }
  1547. $this->assoc = $assoc;
  1548. $this->depth = $depth;
  1549. $this->options = $options;
  1550. $this->maxlength = $maxlength;
  1551. $this->input->on('data', array($this, 'handleData'));
  1552. $this->input->on('end', array($this, 'handleEnd'));
  1553. $this->input->on('error', array($this, 'handleError'));
  1554. $this->input->on('close', array($this, 'close'));
  1555. }
  1556. public function isReadable()
  1557. {
  1558. return !$this->closed;
  1559. }
  1560. public function close()
  1561. {
  1562. if ($this->closed) {
  1563. return;
  1564. }
  1565. $this->closed = true;
  1566. $this->buffer = '';
  1567. $this->input->close();
  1568. $this->emit('close');
  1569. $this->removeAllListeners();
  1570. }
  1571. public function pause()
  1572. {
  1573. $this->input->pause();
  1574. }
  1575. public function resume()
  1576. {
  1577. $this->input->resume();
  1578. }
  1579. public function pipe(WritableStreamInterface $dest, array $options = array())
  1580. {
  1581. Util::pipe($this, $dest, $options);
  1582. return $dest;
  1583. }
  1584. public function handleData($data)
  1585. {
  1586. if (!\is_string($data)) {
  1587. $this->handleError(new \UnexpectedValueException('Expected stream to emit string, but got ' . \gettype($data)));
  1588. return;
  1589. }
  1590. $this->buffer .= $data;
  1591. while (($newline = \strpos($this->buffer, "\n")) !== false && $newline <= $this->maxlength) {
  1592. $data = (string)\substr($this->buffer, 0, $newline);
  1593. $this->buffer = (string)\substr($this->buffer, $newline + 1);
  1594. if ($this->options === 0) {
  1595. $data = \json_decode($data, $this->assoc, $this->depth);
  1596. } else {
  1597. assert(\PHP_VERSION_ID >= 50400);
  1598. $data = \json_decode($data, $this->assoc, $this->depth, $this->options);
  1599. }
  1600. if ($data === null && \json_last_error() !== \JSON_ERROR_NONE) {
  1601. if (\PHP_VERSION_ID > 50500) {
  1602. $errstr = \json_last_error_msg();
  1603. } elseif (\json_last_error() === \JSON_ERROR_SYNTAX) {
  1604. $errstr = 'Syntax error';
  1605. } else {
  1606. $errstr = 'Unknown error';
  1607. }
  1608. return $this->handleError(new \RuntimeException('Unable to decode JSON: ' . $errstr, \json_last_error()));
  1609. }
  1610. $this->emit('data', array($data));
  1611. }
  1612. if (isset($this->buffer[$this->maxlength])) {
  1613. $this->handleError(new \OverflowException('Buffer size exceeded'));
  1614. }
  1615. }
  1616. public function handleEnd()
  1617. {
  1618. if ($this->buffer !== '') {
  1619. $this->handleData("\n");
  1620. }
  1621. if (!$this->closed) {
  1622. $this->emit('end');
  1623. $this->close();
  1624. }
  1625. }
  1626. public function handleError(\Exception $error)
  1627. {
  1628. $this->emit('error', array($error));
  1629. $this->close();
  1630. }
  1631. }
  1632. <?php
  1633. if (PHP_VERSION_ID < 50600) {
  1634. if (!headers_sent()) {
  1635. header('HTTP/1.1 500 Internal Server Error');
  1636. }
  1637. $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
  1638. if (!ini_get('display_errors')) {
  1639. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  1640. fwrite(STDERR, $err);
  1641. } elseif (!headers_sent()) {
  1642. echo $err;
  1643. }
  1644. }
  1645. throw new RuntimeException($err);
  1646. }
  1647. require_once __DIR__ . '/composer/autoload_real.php';
  1648. return ComposerAutoloaderInit5516c75849ea283eeb16cdd35a9ac4cd::getLoader();
  1649. <?php
  1650. $vendorDir = dirname(__DIR__);
  1651. $baseDir = dirname($vendorDir);
  1652. return array(
  1653. );
  1654. <?php
  1655. declare(strict_types=1);
  1656. namespace Composer\XdebugHandler;
  1657. /**
  1658. @phpstan-type
  1659. */
  1660. class PhpConfig
  1661. {
  1662. public function useOriginal(): array
  1663. {
  1664. $this->getDataAndReset();
  1665. return [];
  1666. }
  1667. public function useStandard(): array
  1668. {
  1669. $data = $this->getDataAndReset();
  1670. if ($data !== null) {
  1671. return ['-n', '-c', $data['tmpIni']];
  1672. }
  1673. return [];
  1674. }
  1675. public function usePersistent(): array
  1676. {
  1677. $data = $this->getDataAndReset();
  1678. if ($data !== null) {
  1679. $this->updateEnv('PHPRC', $data['tmpIni']);
  1680. $this->updateEnv('PHP_INI_SCAN_DIR', '');
  1681. }
  1682. return [];
  1683. }
  1684. /**
  1685. @phpstan-return
  1686. */
  1687. private function getDataAndReset(): ?array
  1688. {
  1689. $data = XdebugHandler::getRestartSettings();
  1690. if ($data !== null) {
  1691. $this->updateEnv('PHPRC', $data['phprc']);
  1692. $this->updateEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
  1693. }
  1694. return $data;
  1695. }
  1696. private function updateEnv(string $name, $value): void
  1697. {
  1698. Process::setEnv($name, false !== $value ? $value : null);
  1699. }
  1700. }
  1701. <?php
  1702. declare(strict_types=1);
  1703. namespace Composer\XdebugHandler;
  1704. use Psr\Log\LoggerInterface;
  1705. use Psr\Log\LogLevel;
  1706. class Status
  1707. {
  1708. const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
  1709. const CHECK = 'Check';
  1710. const ERROR = 'Error';
  1711. const INFO = 'Info';
  1712. const NORESTART = 'NoRestart';
  1713. const RESTART = 'Restart';
  1714. const RESTARTING = 'Restarting';
  1715. const RESTARTED = 'Restarted';
  1716. private $debug;
  1717. private $envAllowXdebug;
  1718. private $loaded;
  1719. private $logger;
  1720. private $modeOff;
  1721. private $time;
  1722. public function __construct(string $envAllowXdebug, bool $debug)
  1723. {
  1724. $start = getenv(self::ENV_RESTART);
  1725. Process::setEnv(self::ENV_RESTART);
  1726. $this->time = is_numeric($start) ? round((microtime(true) - $start) * 1000) : 0;
  1727. $this->envAllowXdebug = $envAllowXdebug;
  1728. $this->debug = $debug && defined('STDERR');
  1729. $this->modeOff = false;
  1730. }
  1731. public function setLogger(LoggerInterface $logger): void
  1732. {
  1733. $this->logger = $logger;
  1734. }
  1735. public function report(string $op, ?string $data): void
  1736. {
  1737. if ($this->logger !== null || $this->debug) {
  1738. $param = (string) $data;
  1739. switch($op) {
  1740. case self::CHECK:
  1741. $this->reportCheck($param);
  1742. break;
  1743. case self::ERROR:
  1744. $this->reportError($param);
  1745. break;
  1746. case self::INFO:
  1747. $this->reportInfo($param);
  1748. break;
  1749. case self::NORESTART:
  1750. $this->reportNoRestart();
  1751. break;
  1752. case self::RESTART:
  1753. $this->reportRestart();
  1754. break;
  1755. case self::RESTARTED:
  1756. $this->reportRestarted();
  1757. break;
  1758. case self::RESTARTING:
  1759. $this->reportRestarting($param);
  1760. break;
  1761. default:
  1762. throw new \InvalidArgumentException('Unknown op handler: '.$op);
  1763. }
  1764. }
  1765. }
  1766. private function output(string $text, ?string $level = null): void
  1767. {
  1768. if ($this->logger !== null) {
  1769. $this->logger->log($level !== null ? $level: LogLevel::DEBUG, $text);
  1770. }
  1771. if ($this->debug) {
  1772. fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
  1773. }
  1774. }
  1775. private function reportCheck(string $loaded): void
  1776. {
  1777. list($version, $mode) = explode('|', $loaded);
  1778. if ($version !== '') {
  1779. $this->loaded = '('.$version.')'.($mode !== '' ? ' xdebug.mode='.$mode : '');
  1780. }
  1781. $this->modeOff = $mode === 'off';
  1782. $this->output('Checking '.$this->envAllowXdebug);
  1783. }
  1784. private function reportError(string $error): void
  1785. {
  1786. $this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
  1787. }
  1788. private function reportInfo(string $info): void
  1789. {
  1790. $this->output($info);
  1791. }
  1792. private function reportNoRestart(): void
  1793. {
  1794. $this->output($this->getLoadedMessage());
  1795. if ($this->loaded !== null) {
  1796. $text = sprintf('No restart (%s)', $this->getEnvAllow());
  1797. if (!((bool) getenv($this->envAllowXdebug))) {
  1798. $text .= ' Allowed by '.($this->modeOff ? 'xdebug.mode' : 'application');
  1799. }
  1800. $this->output($text);
  1801. }
  1802. }
  1803. private function reportRestart(): void
  1804. {
  1805. $this->output($this->getLoadedMessage());
  1806. Process::setEnv(self::ENV_RESTART, (string) microtime(true));
  1807. }
  1808. private function reportRestarted(): void
  1809. {
  1810. $loaded = $this->getLoadedMessage();
  1811. $text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
  1812. $level = $this->loaded !== null ? LogLevel::WARNING : null;
  1813. $this->output($text, $level);
  1814. }
  1815. private function reportRestarting(string $command): void
  1816. {
  1817. $text = sprintf('Process restarting (%s)', $this->getEnvAllow());
  1818. $this->output($text);
  1819. $text = 'Running: '.$command;
  1820. $this->output($text);
  1821. }
  1822. private function getEnvAllow(): string
  1823. {
  1824. return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
  1825. }
  1826. private function getLoadedMessage(): string
  1827. {
  1828. $loaded = $this->loaded !== null ? sprintf('loaded %s', $this->loaded) : 'not loaded';
  1829. return 'The Xdebug extension is '.$loaded;
  1830. }
  1831. }
  1832. <?php
  1833. declare(strict_types=1);
  1834. namespace Composer\XdebugHandler;
  1835. use Composer\Pcre\Preg;
  1836. use Psr\Log\LoggerInterface;
  1837. /**
  1838. @phpstan-import-type
  1839. */
  1840. class XdebugHandler
  1841. {
  1842. const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
  1843. const SUFFIX_INIS = '_ORIGINAL_INIS';
  1844. const RESTART_ID = 'internal';
  1845. const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
  1846. const DEBUG = 'XDEBUG_HANDLER_DEBUG';
  1847. protected $tmpIni;
  1848. private static $inRestart;
  1849. private static $name;
  1850. private static $skipped;
  1851. private static $xdebugActive;
  1852. private static $xdebugMode;
  1853. private static $xdebugVersion;
  1854. private $cli;
  1855. private $debug;
  1856. private $envAllowXdebug;
  1857. private $envOriginalInis;
  1858. private $persistent;
  1859. private $script;
  1860. private $statusWriter;
  1861. public function __construct(string $envPrefix)
  1862. {
  1863. if ($envPrefix === '') {
  1864. throw new \RuntimeException('Invalid constructor parameter');
  1865. }
  1866. self::$name = strtoupper($envPrefix);
  1867. $this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
  1868. $this->envOriginalInis = self::$name.self::SUFFIX_INIS;
  1869. self::setXdebugDetails();
  1870. self::$inRestart = false;
  1871. if ($this->cli = PHP_SAPI === 'cli') {
  1872. $this->debug = (string) getenv(self::DEBUG);
  1873. }
  1874. $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
  1875. }
  1876. public function setLogger(LoggerInterface $logger): self
  1877. {
  1878. $this->statusWriter->setLogger($logger);
  1879. return $this;
  1880. }
  1881. public function setMainScript(string $script): self
  1882. {
  1883. $this->script = $script;
  1884. return $this;
  1885. }
  1886. public function setPersistent(): self
  1887. {
  1888. $this->persistent = true;
  1889. return $this;
  1890. }
  1891. public function check(): void
  1892. {
  1893. $this->notify(Status::CHECK, self::$xdebugVersion.'|'.self::$xdebugMode);
  1894. $envArgs = explode('|', (string) getenv($this->envAllowXdebug));
  1895. if (!((bool) $envArgs[0]) && $this->requiresRestart(self::$xdebugActive)) {
  1896. $this->notify(Status::RESTART);
  1897. $command = $this->prepareRestart();
  1898. if ($command !== null) {
  1899. $this->restart($command);
  1900. }
  1901. return;
  1902. }
  1903. if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
  1904. $this->notify(Status::RESTARTED);
  1905. Process::setEnv($this->envAllowXdebug);
  1906. self::$inRestart = true;
  1907. if (self::$xdebugVersion === null) {
  1908. self::$skipped = $envArgs[1];
  1909. }
  1910. $this->tryEnableSignals();
  1911. $this->setEnvRestartSettings($envArgs);
  1912. return;
  1913. }
  1914. $this->notify(Status::NORESTART);
  1915. $settings = self::getRestartSettings();
  1916. if ($settings !== null) {
  1917. $this->syncSettings($settings);
  1918. }
  1919. }
  1920. public static function getAllIniFiles(): array
  1921. {
  1922. if (self::$name !== null) {
  1923. $env = getenv(self::$name.self::SUFFIX_INIS);
  1924. if (false !== $env) {
  1925. return explode(PATH_SEPARATOR, $env);
  1926. }
  1927. }
  1928. $paths = [(string) php_ini_loaded_file()];
  1929. $scanned = php_ini_scanned_files();
  1930. if ($scanned !== false) {
  1931. $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
  1932. }
  1933. return $paths;
  1934. }
  1935. /**
  1936. @phpstan-return
  1937. */
  1938. public static function getRestartSettings(): ?array
  1939. {
  1940. $envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
  1941. if (count($envArgs) !== 6
  1942. || (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
  1943. return null;
  1944. }
  1945. return [
  1946. 'tmpIni' => $envArgs[0],
  1947. 'scannedInis' => (bool) $envArgs[1],
  1948. 'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
  1949. 'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
  1950. 'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
  1951. 'skipped' => $envArgs[5],
  1952. ];
  1953. }
  1954. public static function getSkippedVersion(): string
  1955. {
  1956. return (string) self::$skipped;
  1957. }
  1958. public static function isXdebugActive(): bool
  1959. {
  1960. self::setXdebugDetails();
  1961. return self::$xdebugActive;
  1962. }
  1963. protected function requiresRestart(bool $default): bool
  1964. {
  1965. return $default;
  1966. }
  1967. protected function restart(array $command): void
  1968. {
  1969. $this->doRestart($command);
  1970. }
  1971. /**
  1972. @phpstan-return
  1973. */
  1974. private function doRestart(array $command): void
  1975. {
  1976. if (PHP_VERSION_ID >= 70400) {
  1977. $cmd = $command;
  1978. $displayCmd = sprintf('[%s]', implode(', ', $cmd));
  1979. } else {
  1980. $cmd = Process::escapeShellCommand($command);
  1981. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  1982. $cmd = '"'.$cmd.'"';
  1983. }
  1984. $displayCmd = $cmd;
  1985. }
  1986. $this->tryEnableSignals();
  1987. $this->notify(Status::RESTARTING, $displayCmd);
  1988. $process = proc_open($cmd, [], $pipes);
  1989. if (is_resource($process)) {
  1990. $exitCode = proc_close($process);
  1991. }
  1992. if (!isset($exitCode)) {
  1993. $this->notify(Status::ERROR, 'Unable to restart process');
  1994. $exitCode = -1;
  1995. } else {
  1996. $this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
  1997. }
  1998. if ($this->debug === '2') {
  1999. $this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
  2000. } else {
  2001. @unlink((string) $this->tmpIni);
  2002. }
  2003. exit($exitCode);
  2004. }
  2005. private function prepareRestart(): ?array
  2006. {
  2007. if (!$this->cli) {
  2008. $this->notify(Status::ERROR, 'Unsupported SAPI: '.PHP_SAPI);
  2009. return null;
  2010. }
  2011. if (($argv = $this->checkServerArgv()) === null) {
  2012. $this->notify(Status::ERROR, '$_SERVER[argv] is not as expected');
  2013. return null;
  2014. }
  2015. if (!$this->checkConfiguration($info)) {
  2016. $this->notify(Status::ERROR, $info);
  2017. return null;
  2018. }
  2019. $mainScript = (string) $this->script;
  2020. if (!$this->checkMainScript($mainScript, $argv)) {
  2021. $this->notify(Status::ERROR, 'Unable to access main script: '.$mainScript);
  2022. return null;
  2023. }
  2024. $tmpDir = sys_get_temp_dir();
  2025. $iniError = 'Unable to create temp ini file at: '.$tmpDir;
  2026. if (($tmpfile = @tempnam($tmpDir, '')) === false) {
  2027. $this->notify(Status::ERROR, $iniError);
  2028. return null;
  2029. }
  2030. $error = null;
  2031. $iniFiles = self::getAllIniFiles();
  2032. $scannedInis = count($iniFiles) > 1;
  2033. if (!$this->writeTmpIni($tmpfile, $iniFiles, $error)) {
  2034. $this->notify(Status::ERROR, $error ?? $iniError);
  2035. @unlink($tmpfile);
  2036. return null;
  2037. }
  2038. if (!$this->setEnvironment($scannedInis, $iniFiles, $tmpfile)) {
  2039. $this->notify(Status::ERROR, 'Unable to set environment variables');
  2040. @unlink($tmpfile);
  2041. return null;
  2042. }
  2043. $this->tmpIni = $tmpfile;
  2044. return $this->getCommand($argv, $tmpfile, $mainScript);
  2045. }
  2046. private function writeTmpIni(string $tmpFile, array $iniFiles, ?string &$error): bool
  2047. {
  2048. if ($iniFiles[0] === '') {
  2049. array_shift($iniFiles);
  2050. }
  2051. $content = '';
  2052. $sectionRegex = '/^\s*\[(?:PATH|HOST)\s*=/mi';
  2053. $xdebugRegex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
  2054. foreach ($iniFiles as $file) {
  2055. if (($data = @file_get_contents($file)) === false) {
  2056. $error = 'Unable to read ini: '.$file;
  2057. return false;
  2058. }
  2059. if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches)) {
  2060. $data = substr($data, 0, $matches[0][1]);
  2061. }
  2062. $content .= Preg::replace($xdebugRegex, ';$1', $data).PHP_EOL;
  2063. }
  2064. $config = parse_ini_string($content);
  2065. $loaded = ini_get_all(null, false);
  2066. if (false === $config || false === $loaded) {
  2067. $error = 'Unable to parse ini data';
  2068. return false;
  2069. }
  2070. $content .= $this->mergeLoadedConfig($loaded, $config);
  2071. $content .= 'opcache.enable_cli=0'.PHP_EOL;
  2072. return (bool) @file_put_contents($tmpFile, $content);
  2073. }
  2074. private function getCommand(array $argv, string $tmpIni, string $mainScript): array
  2075. {
  2076. $php = [PHP_BINARY];
  2077. $args = array_slice($argv, 1);
  2078. if (!$this->persistent) {
  2079. array_push($php, '-n', '-c', $tmpIni);
  2080. }
  2081. return array_merge($php, [$mainScript], $args);
  2082. }
  2083. private function setEnvironment(bool $scannedInis, array $iniFiles, string $tmpIni): bool
  2084. {
  2085. $scanDir = getenv('PHP_INI_SCAN_DIR');
  2086. $phprc = getenv('PHPRC');
  2087. if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
  2088. return false;
  2089. }
  2090. if ($this->persistent) {
  2091. if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$tmpIni)) {
  2092. return false;
  2093. }
  2094. }
  2095. $envArgs = [
  2096. self::RESTART_ID,
  2097. self::$xdebugVersion,
  2098. (int) $scannedInis,
  2099. false === $scanDir ? '*' : $scanDir,
  2100. false === $phprc ? '*' : $phprc,
  2101. ];
  2102. return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
  2103. }
  2104. private function notify(string $op, ?string $data = null): void
  2105. {
  2106. $this->statusWriter->report($op, $data);
  2107. }
  2108. private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): string
  2109. {
  2110. $content = '';
  2111. foreach ($loadedConfig as $name => $value) {
  2112. if (!is_string($value)
  2113. || strpos($name, 'xdebug') === 0
  2114. || $name === 'apc.mmap_file_mask') {
  2115. continue;
  2116. }
  2117. if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
  2118. $content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
  2119. }
  2120. }
  2121. return $content;
  2122. }
  2123. private function checkMainScript(string &$mainScript, array $argv): bool
  2124. {
  2125. if ($mainScript !== '') {
  2126. return file_exists($mainScript) || '--' === $mainScript;
  2127. }
  2128. if (file_exists($mainScript = $argv[0])) {
  2129. return true;
  2130. }
  2131. $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  2132. $main = end($trace);
  2133. if ($main !== false && isset($main['file'])) {
  2134. return file_exists($mainScript = $main['file']);
  2135. }
  2136. return false;
  2137. }
  2138. private function setEnvRestartSettings(array $envArgs): void
  2139. {
  2140. $settings = [
  2141. php_ini_loaded_file(),
  2142. $envArgs[2],
  2143. $envArgs[3],
  2144. $envArgs[4],
  2145. getenv($this->envOriginalInis),
  2146. self::$skipped,
  2147. ];
  2148. Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
  2149. }
  2150. /**
  2151. @phpstan-param
  2152. */
  2153. private function syncSettings(array $settings): void
  2154. {
  2155. if (false === getenv($this->envOriginalInis)) {
  2156. Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
  2157. }
  2158. self::$skipped = $settings['skipped'];
  2159. $this->notify(Status::INFO, 'Process called with existing restart settings');
  2160. }
  2161. private function checkConfiguration(?string &$info): bool
  2162. {
  2163. if (!function_exists('proc_open')) {
  2164. $info = 'proc_open function is disabled';
  2165. return false;
  2166. }
  2167. if (!file_exists(PHP_BINARY)) {
  2168. $info = 'PHP_BINARY is not available';
  2169. return false;
  2170. }
  2171. if (extension_loaded('uopz') && !((bool) ini_get('uopz.disable'))) {
  2172. if (function_exists('uopz_allow_exit')) {
  2173. @uopz_allow_exit(true);
  2174. } else {
  2175. $info = 'uopz extension is not compatible';
  2176. return false;
  2177. }
  2178. }
  2179. if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 70400) {
  2180. $workingDir = getcwd();
  2181. if ($workingDir === false) {
  2182. $info = 'unable to determine working directory';
  2183. return false;
  2184. }
  2185. if (0 === strpos($workingDir, '\\\\')) {
  2186. $info = 'cmd.exe does not support UNC paths: '.$workingDir;
  2187. return false;
  2188. }
  2189. }
  2190. return true;
  2191. }
  2192. private function tryEnableSignals(): void
  2193. {
  2194. if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
  2195. pcntl_async_signals(true);
  2196. $message = 'Async signals enabled';
  2197. if (!self::$inRestart) {
  2198. pcntl_signal(SIGINT, SIG_IGN);
  2199. } elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
  2200. pcntl_signal(SIGINT, SIG_DFL);
  2201. }
  2202. }
  2203. if (!self::$inRestart && function_exists('sapi_windows_set_ctrl_handler')) {
  2204. sapi_windows_set_ctrl_handler(function ($evt) {});
  2205. }
  2206. }
  2207. private function checkServerArgv(): ?array
  2208. {
  2209. $result = [];
  2210. if (isset($_SERVER['argv']) && is_array($_SERVER['argv'])) {
  2211. foreach ($_SERVER['argv'] as $value) {
  2212. if (!is_string($value)) {
  2213. return null;
  2214. }
  2215. $result[] = $value;
  2216. }
  2217. }
  2218. return count($result) > 0 ? $result : null;
  2219. }
  2220. private static function setXdebugDetails(): void
  2221. {
  2222. if (self::$xdebugActive !== null) {
  2223. return;
  2224. }
  2225. self::$xdebugActive = false;
  2226. if (!extension_loaded('xdebug')) {
  2227. return;
  2228. }
  2229. $version = phpversion('xdebug');
  2230. self::$xdebugVersion = $version !== false ? $version : 'unknown';
  2231. if (version_compare(self::$xdebugVersion, '3.1', '>=')) {
  2232. $modes = xdebug_info('mode');
  2233. self::$xdebugMode = count($modes) === 0 ? 'off' : implode(',', $modes);
  2234. self::$xdebugActive = self::$xdebugMode !== 'off';
  2235. return;
  2236. }
  2237. $iniMode = ini_get('xdebug.mode');
  2238. if ($iniMode === false) {
  2239. self::$xdebugActive = true;
  2240. return;
  2241. }
  2242. $envMode = (string) getenv('XDEBUG_MODE');
  2243. if ($envMode !== '') {
  2244. self::$xdebugMode = $envMode;
  2245. } else {
  2246. self::$xdebugMode = $iniMode !== '' ? $iniMode : 'off';
  2247. }
  2248. if (Preg::isMatch('/^,+$/', str_replace(' ', '', self::$xdebugMode))) {
  2249. self::$xdebugMode = 'off';
  2250. }
  2251. self::$xdebugActive = self::$xdebugMode !== 'off';
  2252. }
  2253. }
  2254. <?php
  2255. declare(strict_types=1);
  2256. namespace Composer\XdebugHandler;
  2257. use Composer\Pcre\Preg;
  2258. class Process
  2259. {
  2260. public static function escape(string $arg, bool $meta = true, bool $module = false): string
  2261. {
  2262. if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
  2263. return "'".str_replace("'", "'\\''", $arg)."'";
  2264. }
  2265. $quote = strpbrk($arg, " \t") !== false || $arg === '';
  2266. $arg = Preg::replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
  2267. $dquotes = (bool) $dquotes;
  2268. if ($meta) {
  2269. $meta = $dquotes || Preg::isMatch('/%[^%]+%/', $arg);
  2270. if (!$meta) {
  2271. $quote = $quote || strpbrk($arg, '^&|<>()') !== false;
  2272. } elseif ($module && !$dquotes && $quote) {
  2273. $meta = false;
  2274. }
  2275. }
  2276. if ($quote) {
  2277. $arg = '"'.(Preg::replace('/(\\\\*)$/', '$1$1', $arg)).'"';
  2278. }
  2279. if ($meta) {
  2280. $arg = Preg::replace('/(["^&|<>()%])/', '^$1', $arg);
  2281. }
  2282. return $arg;
  2283. }
  2284. public static function escapeShellCommand(array $args): string
  2285. {
  2286. $command = '';
  2287. $module = array_shift($args);
  2288. if ($module !== null) {
  2289. $command = self::escape($module, true, true);
  2290. foreach ($args as $arg) {
  2291. $command .= ' '.self::escape($arg);
  2292. }
  2293. }
  2294. return $command;
  2295. }
  2296. public static function setEnv(string $name, ?string $value = null): bool
  2297. {
  2298. $unset = null === $value;
  2299. if (!putenv($unset ? $name : $name.'='.$value)) {
  2300. return false;
  2301. }
  2302. if ($unset) {
  2303. unset($_SERVER[$name]);
  2304. } else {
  2305. $_SERVER[$name] = $value;
  2306. }
  2307. if (false !== stripos((string) ini_get('variables_order'), 'E')) {
  2308. if ($unset) {
  2309. unset($_ENV[$name]);
  2310. } else {
  2311. $_ENV[$name] = $value;
  2312. }
  2313. }
  2314. return true;
  2315. }
  2316. }
  2317. <?php
  2318. namespace Composer\Autoload;
  2319. class ClassLoader
  2320. {
  2321. private static $includeFile;
  2322. private $vendorDir;
  2323. private $prefixLengthsPsr4 = array();
  2324. private $prefixDirsPsr4 = array();
  2325. private $fallbackDirsPsr4 = array();
  2326. private $prefixesPsr0 = array();
  2327. private $fallbackDirsPsr0 = array();
  2328. private $useIncludePath = false;
  2329. private $classMap = array();
  2330. private $classMapAuthoritative = false;
  2331. private $missingClasses = array();
  2332. private $apcuPrefix;
  2333. private static $registeredLoaders = array();
  2334. public function __construct($vendorDir = null)
  2335. {
  2336. $this->vendorDir = $vendorDir;
  2337. self::initializeIncludeClosure();
  2338. }
  2339. public function getPrefixes()
  2340. {
  2341. if (!empty($this->prefixesPsr0)) {
  2342. return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
  2343. }
  2344. return array();
  2345. }
  2346. public function getPrefixesPsr4()
  2347. {
  2348. return $this->prefixDirsPsr4;
  2349. }
  2350. public function getFallbackDirs()
  2351. {
  2352. return $this->fallbackDirsPsr0;
  2353. }
  2354. public function getFallbackDirsPsr4()
  2355. {
  2356. return $this->fallbackDirsPsr4;
  2357. }
  2358. public function getClassMap()
  2359. {
  2360. return $this->classMap;
  2361. }
  2362. public function addClassMap(array $classMap)
  2363. {
  2364. if ($this->classMap) {
  2365. $this->classMap = array_merge($this->classMap, $classMap);
  2366. } else {
  2367. $this->classMap = $classMap;
  2368. }
  2369. }
  2370. public function add($prefix, $paths, $prepend = false)
  2371. {
  2372. $paths = (array) $paths;
  2373. if (!$prefix) {
  2374. if ($prepend) {
  2375. $this->fallbackDirsPsr0 = array_merge(
  2376. $paths,
  2377. $this->fallbackDirsPsr0
  2378. );
  2379. } else {
  2380. $this->fallbackDirsPsr0 = array_merge(
  2381. $this->fallbackDirsPsr0,
  2382. $paths
  2383. );
  2384. }
  2385. return;
  2386. }
  2387. $first = $prefix[0];
  2388. if (!isset($this->prefixesPsr0[$first][$prefix])) {
  2389. $this->prefixesPsr0[$first][$prefix] = $paths;
  2390. return;
  2391. }
  2392. if ($prepend) {
  2393. $this->prefixesPsr0[$first][$prefix] = array_merge(
  2394. $paths,
  2395. $this->prefixesPsr0[$first][$prefix]
  2396. );
  2397. } else {
  2398. $this->prefixesPsr0[$first][$prefix] = array_merge(
  2399. $this->prefixesPsr0[$first][$prefix],
  2400. $paths
  2401. );
  2402. }
  2403. }
  2404. public function addPsr4($prefix, $paths, $prepend = false)
  2405. {
  2406. $paths = (array) $paths;
  2407. if (!$prefix) {
  2408. if ($prepend) {
  2409. $this->fallbackDirsPsr4 = array_merge(
  2410. $paths,
  2411. $this->fallbackDirsPsr4
  2412. );
  2413. } else {
  2414. $this->fallbackDirsPsr4 = array_merge(
  2415. $this->fallbackDirsPsr4,
  2416. $paths
  2417. );
  2418. }
  2419. } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
  2420. $length = strlen($prefix);
  2421. if ('\\' !== $prefix[$length - 1]) {
  2422. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  2423. }
  2424. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  2425. $this->prefixDirsPsr4[$prefix] = $paths;
  2426. } elseif ($prepend) {
  2427. $this->prefixDirsPsr4[$prefix] = array_merge(
  2428. $paths,
  2429. $this->prefixDirsPsr4[$prefix]
  2430. );
  2431. } else {
  2432. $this->prefixDirsPsr4[$prefix] = array_merge(
  2433. $this->prefixDirsPsr4[$prefix],
  2434. $paths
  2435. );
  2436. }
  2437. }
  2438. public function set($prefix, $paths)
  2439. {
  2440. if (!$prefix) {
  2441. $this->fallbackDirsPsr0 = (array) $paths;
  2442. } else {
  2443. $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
  2444. }
  2445. }
  2446. public function setPsr4($prefix, $paths)
  2447. {
  2448. if (!$prefix) {
  2449. $this->fallbackDirsPsr4 = (array) $paths;
  2450. } else {
  2451. $length = strlen($prefix);
  2452. if ('\\' !== $prefix[$length - 1]) {
  2453. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  2454. }
  2455. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  2456. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  2457. }
  2458. }
  2459. public function setUseIncludePath($useIncludePath)
  2460. {
  2461. $this->useIncludePath = $useIncludePath;
  2462. }
  2463. public function getUseIncludePath()
  2464. {
  2465. return $this->useIncludePath;
  2466. }
  2467. public function setClassMapAuthoritative($classMapAuthoritative)
  2468. {
  2469. $this->classMapAuthoritative = $classMapAuthoritative;
  2470. }
  2471. public function isClassMapAuthoritative()
  2472. {
  2473. return $this->classMapAuthoritative;
  2474. }
  2475. public function setApcuPrefix($apcuPrefix)
  2476. {
  2477. $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
  2478. }
  2479. public function getApcuPrefix()
  2480. {
  2481. return $this->apcuPrefix;
  2482. }
  2483. public function register($prepend = false)
  2484. {
  2485. spl_autoload_register(array($this, 'loadClass'), true, $prepend);
  2486. if (null === $this->vendorDir) {
  2487. return;
  2488. }
  2489. if ($prepend) {
  2490. self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
  2491. } else {
  2492. unset(self::$registeredLoaders[$this->vendorDir]);
  2493. self::$registeredLoaders[$this->vendorDir] = $this;
  2494. }
  2495. }
  2496. public function unregister()
  2497. {
  2498. spl_autoload_unregister(array($this, 'loadClass'));
  2499. if (null !== $this->vendorDir) {
  2500. unset(self::$registeredLoaders[$this->vendorDir]);
  2501. }
  2502. }
  2503. public function loadClass($class)
  2504. {
  2505. if ($file = $this->findFile($class)) {
  2506. $includeFile = self::$includeFile;
  2507. $includeFile($file);
  2508. return true;
  2509. }
  2510. return null;
  2511. }
  2512. public function findFile($class)
  2513. {
  2514. if (isset($this->classMap[$class])) {
  2515. return $this->classMap[$class];
  2516. }
  2517. if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
  2518. return false;
  2519. }
  2520. if (null !== $this->apcuPrefix) {
  2521. $file = apcu_fetch($this->apcuPrefix.$class, $hit);
  2522. if ($hit) {
  2523. return $file;
  2524. }
  2525. }
  2526. $file = $this->findFileWithExtension($class, '.php');
  2527. if (false === $file && defined('HHVM_VERSION')) {
  2528. $file = $this->findFileWithExtension($class, '.hh');
  2529. }
  2530. if (null !== $this->apcuPrefix) {
  2531. apcu_add($this->apcuPrefix.$class, $file);
  2532. }
  2533. if (false === $file) {
  2534. $this->missingClasses[$class] = true;
  2535. }
  2536. return $file;
  2537. }
  2538. public static function getRegisteredLoaders()
  2539. {
  2540. return self::$registeredLoaders;
  2541. }
  2542. private function findFileWithExtension($class, $ext)
  2543. {
  2544. $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
  2545. $first = $class[0];
  2546. if (isset($this->prefixLengthsPsr4[$first])) {
  2547. $subPath = $class;
  2548. while (false !== $lastPos = strrpos($subPath, '\\')) {
  2549. $subPath = substr($subPath, 0, $lastPos);
  2550. $search = $subPath . '\\';
  2551. if (isset($this->prefixDirsPsr4[$search])) {
  2552. $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
  2553. foreach ($this->prefixDirsPsr4[$search] as $dir) {
  2554. if (file_exists($file = $dir . $pathEnd)) {
  2555. return $file;
  2556. }
  2557. }
  2558. }
  2559. }
  2560. }
  2561. foreach ($this->fallbackDirsPsr4 as $dir) {
  2562. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
  2563. return $file;
  2564. }
  2565. }
  2566. if (false !== $pos = strrpos($class, '\\')) {
  2567. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  2568. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
  2569. } else {
  2570. $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
  2571. }
  2572. if (isset($this->prefixesPsr0[$first])) {
  2573. foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
  2574. if (0 === strpos($class, $prefix)) {
  2575. foreach ($dirs as $dir) {
  2576. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  2577. return $file;
  2578. }
  2579. }
  2580. }
  2581. }
  2582. }
  2583. foreach ($this->fallbackDirsPsr0 as $dir) {
  2584. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  2585. return $file;
  2586. }
  2587. }
  2588. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
  2589. return $file;
  2590. }
  2591. return false;
  2592. }
  2593. private static function initializeIncludeClosure()
  2594. {
  2595. if (self::$includeFile !== null) {
  2596. return;
  2597. }
  2598. self::$includeFile = \Closure::bind(static function($file) {
  2599. include $file;
  2600. }, null, null);
  2601. }
  2602. }
  2603. <?php
  2604. $vendorDir = dirname(__DIR__);
  2605. $baseDir = dirname($vendorDir);
  2606. return array(
  2607. 'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
  2608. 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
  2609. 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
  2610. 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
  2611. 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
  2612. 'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'),
  2613. 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
  2614. 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
  2615. 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'),
  2616. 'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
  2617. 'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
  2618. 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
  2619. 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
  2620. 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
  2621. 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
  2622. 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
  2623. 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
  2624. 'React\\Stream\\' => array($vendorDir . '/react/stream/src'),
  2625. 'React\\Socket\\' => array($vendorDir . '/react/socket/src'),
  2626. 'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
  2627. 'React\\EventLoop\\' => array($vendorDir . '/react/event-loop/src'),
  2628. 'React\\Dns\\' => array($vendorDir . '/react/dns/src'),
  2629. 'React\\ChildProcess\\' => array($vendorDir . '/react/child-process/src'),
  2630. 'React\\Cache\\' => array($vendorDir . '/react/cache/src'),
  2631. 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
  2632. 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
  2633. 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
  2634. 'PhpCsFixer\\' => array($baseDir . '/src'),
  2635. 'Fidry\\CpuCoreCounter\\' => array($vendorDir . '/fidry/cpu-core-counter/src'),
  2636. 'Evenement\\' => array($vendorDir . '/evenement/evenement/src'),
  2637. 'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
  2638. 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
  2639. 'Composer\\Pcre\\' => array($vendorDir . '/composer/pcre/src'),
  2640. 'Clue\\React\\NDJson\\' => array($vendorDir . '/clue/ndjson-react/src'),
  2641. );
  2642. <?php
  2643. $vendorDir = dirname(__DIR__);
  2644. $baseDir = dirname($vendorDir);
  2645. return array(
  2646. 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
  2647. 'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
  2648. 'Clue\\React\\NDJson\\Decoder' => $vendorDir . '/clue/ndjson-react/src/Decoder.php',
  2649. 'Clue\\React\\NDJson\\Encoder' => $vendorDir . '/clue/ndjson-react/src/Encoder.php',
  2650. 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
  2651. 'Composer\\Pcre\\MatchAllResult' => $vendorDir . '/composer/pcre/src/MatchAllResult.php',
  2652. 'Composer\\Pcre\\MatchAllStrictGroupsResult' => $vendorDir . '/composer/pcre/src/MatchAllStrictGroupsResult.php',
  2653. 'Composer\\Pcre\\MatchAllWithOffsetsResult' => $vendorDir . '/composer/pcre/src/MatchAllWithOffsetsResult.php',
  2654. 'Composer\\Pcre\\MatchResult' => $vendorDir . '/composer/pcre/src/MatchResult.php',
  2655. 'Composer\\Pcre\\MatchStrictGroupsResult' => $vendorDir . '/composer/pcre/src/MatchStrictGroupsResult.php',
  2656. 'Composer\\Pcre\\MatchWithOffsetsResult' => $vendorDir . '/composer/pcre/src/MatchWithOffsetsResult.php',
  2657. 'Composer\\Pcre\\PHPStan\\InvalidRegexPatternRule' => $vendorDir . '/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php',
  2658. 'Composer\\Pcre\\PHPStan\\PregMatchFlags' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchFlags.php',
  2659. 'Composer\\Pcre\\PHPStan\\PregMatchParameterOutTypeExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php',
  2660. 'Composer\\Pcre\\PHPStan\\PregMatchTypeSpecifyingExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php',
  2661. 'Composer\\Pcre\\PHPStan\\PregReplaceCallbackClosureTypeExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php',
  2662. 'Composer\\Pcre\\PHPStan\\UnsafeStrictGroupsCallRule' => $vendorDir . '/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php',
  2663. 'Composer\\Pcre\\PcreException' => $vendorDir . '/composer/pcre/src/PcreException.php',
  2664. 'Composer\\Pcre\\Preg' => $vendorDir . '/composer/pcre/src/Preg.php',
  2665. 'Composer\\Pcre\\Regex' => $vendorDir . '/composer/pcre/src/Regex.php',
  2666. 'Composer\\Pcre\\ReplaceResult' => $vendorDir . '/composer/pcre/src/ReplaceResult.php',
  2667. 'Composer\\Pcre\\UnexpectedNullMatchException' => $vendorDir . '/composer/pcre/src/UnexpectedNullMatchException.php',
  2668. 'Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
  2669. 'Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php',
  2670. 'Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php',
  2671. 'Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
  2672. 'Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
  2673. 'Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php',
  2674. 'Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
  2675. 'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
  2676. 'Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php',
  2677. 'Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php',
  2678. 'Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
  2679. 'Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
  2680. 'Composer\\XdebugHandler\\PhpConfig' => $vendorDir . '/composer/xdebug-handler/src/PhpConfig.php',
  2681. 'Composer\\XdebugHandler\\Process' => $vendorDir . '/composer/xdebug-handler/src/Process.php',
  2682. 'Composer\\XdebugHandler\\Status' => $vendorDir . '/composer/xdebug-handler/src/Status.php',
  2683. 'Composer\\XdebugHandler\\XdebugHandler' => $vendorDir . '/composer/xdebug-handler/src/XdebugHandler.php',
  2684. 'Evenement\\EventEmitter' => $vendorDir . '/evenement/evenement/src/EventEmitter.php',
  2685. 'Evenement\\EventEmitterInterface' => $vendorDir . '/evenement/evenement/src/EventEmitterInterface.php',
  2686. 'Evenement\\EventEmitterTrait' => $vendorDir . '/evenement/evenement/src/EventEmitterTrait.php',
  2687. 'Fidry\\CpuCoreCounter\\CpuCoreCounter' => $vendorDir . '/fidry/cpu-core-counter/src/CpuCoreCounter.php',
  2688. 'Fidry\\CpuCoreCounter\\Diagnoser' => $vendorDir . '/fidry/cpu-core-counter/src/Diagnoser.php',
  2689. 'Fidry\\CpuCoreCounter\\Executor\\ProcOpenExecutor' => $vendorDir . '/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.php',
  2690. 'Fidry\\CpuCoreCounter\\Executor\\ProcessExecutor' => $vendorDir . '/fidry/cpu-core-counter/src/Executor/ProcessExecutor.php',
  2691. 'Fidry\\CpuCoreCounter\\Finder\\CmiCmdletLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.php',
  2692. 'Fidry\\CpuCoreCounter\\Finder\\CmiCmdletPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.php',
  2693. 'Fidry\\CpuCoreCounter\\Finder\\CpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.php',
  2694. 'Fidry\\CpuCoreCounter\\Finder\\CpuInfoFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.php',
  2695. 'Fidry\\CpuCoreCounter\\Finder\\DummyCpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.php',
  2696. 'Fidry\\CpuCoreCounter\\Finder\\EnvVariableFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.php',
  2697. 'Fidry\\CpuCoreCounter\\Finder\\FinderRegistry' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/FinderRegistry.php',
  2698. 'Fidry\\CpuCoreCounter\\Finder\\HwLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.php',
  2699. 'Fidry\\CpuCoreCounter\\Finder\\HwPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php',
  2700. 'Fidry\\CpuCoreCounter\\Finder\\LscpuLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.php',
  2701. 'Fidry\\CpuCoreCounter\\Finder\\LscpuPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.php',
  2702. 'Fidry\\CpuCoreCounter\\Finder\\NProcFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NProcFinder.php',
  2703. 'Fidry\\CpuCoreCounter\\Finder\\NProcessorFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NProcessorFinder.php',
  2704. 'Fidry\\CpuCoreCounter\\Finder\\NullCpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.php',
  2705. 'Fidry\\CpuCoreCounter\\Finder\\OnlyInPowerShellFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.php',
  2706. 'Fidry\\CpuCoreCounter\\Finder\\OnlyOnOSFamilyFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.php',
  2707. 'Fidry\\CpuCoreCounter\\Finder\\ProcOpenBasedFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.php',
  2708. 'Fidry\\CpuCoreCounter\\Finder\\SkipOnOSFamilyFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.php',
  2709. 'Fidry\\CpuCoreCounter\\Finder\\WindowsRegistryLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php',
  2710. 'Fidry\\CpuCoreCounter\\Finder\\WmicLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.php',
  2711. 'Fidry\\CpuCoreCounter\\Finder\\WmicPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.php',
  2712. 'Fidry\\CpuCoreCounter\\Finder\\_NProcessorFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.php',
  2713. 'Fidry\\CpuCoreCounter\\NumberOfCpuCoreNotFound' => $vendorDir . '/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php',
  2714. 'Fidry\\CpuCoreCounter\\ParallelisationResult' => $vendorDir . '/fidry/cpu-core-counter/src/ParallelisationResult.php',
  2715. 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
  2716. 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
  2717. 'PhpCsFixer\\AbstractDoctrineAnnotationFixer' => $baseDir . '/src/AbstractDoctrineAnnotationFixer.php',
  2718. 'PhpCsFixer\\AbstractFixer' => $baseDir . '/src/AbstractFixer.php',
  2719. 'PhpCsFixer\\AbstractFopenFlagFixer' => $baseDir . '/src/AbstractFopenFlagFixer.php',
  2720. 'PhpCsFixer\\AbstractFunctionReferenceFixer' => $baseDir . '/src/AbstractFunctionReferenceFixer.php',
  2721. 'PhpCsFixer\\AbstractNoUselessElseFixer' => $baseDir . '/src/AbstractNoUselessElseFixer.php',
  2722. 'PhpCsFixer\\AbstractPhpdocToTypeDeclarationFixer' => $baseDir . '/src/AbstractPhpdocToTypeDeclarationFixer.php',
  2723. 'PhpCsFixer\\AbstractPhpdocTypesFixer' => $baseDir . '/src/AbstractPhpdocTypesFixer.php',
  2724. 'PhpCsFixer\\AbstractProxyFixer' => $baseDir . '/src/AbstractProxyFixer.php',
  2725. 'PhpCsFixer\\Cache\\Cache' => $baseDir . '/src/Cache/Cache.php',
  2726. 'PhpCsFixer\\Cache\\CacheInterface' => $baseDir . '/src/Cache/CacheInterface.php',
  2727. 'PhpCsFixer\\Cache\\CacheManagerInterface' => $baseDir . '/src/Cache/CacheManagerInterface.php',
  2728. 'PhpCsFixer\\Cache\\Directory' => $baseDir . '/src/Cache/Directory.php',
  2729. 'PhpCsFixer\\Cache\\DirectoryInterface' => $baseDir . '/src/Cache/DirectoryInterface.php',
  2730. 'PhpCsFixer\\Cache\\FileCacheManager' => $baseDir . '/src/Cache/FileCacheManager.php',
  2731. 'PhpCsFixer\\Cache\\FileHandler' => $baseDir . '/src/Cache/FileHandler.php',
  2732. 'PhpCsFixer\\Cache\\FileHandlerInterface' => $baseDir . '/src/Cache/FileHandlerInterface.php',
  2733. 'PhpCsFixer\\Cache\\NullCacheManager' => $baseDir . '/src/Cache/NullCacheManager.php',
  2734. 'PhpCsFixer\\Cache\\Signature' => $baseDir . '/src/Cache/Signature.php',
  2735. 'PhpCsFixer\\Cache\\SignatureInterface' => $baseDir . '/src/Cache/SignatureInterface.php',
  2736. 'PhpCsFixer\\Config' => $baseDir . '/src/Config.php',
  2737. 'PhpCsFixer\\ConfigInterface' => $baseDir . '/src/ConfigInterface.php',
  2738. 'PhpCsFixer\\ConfigurationException\\InvalidConfigurationException' => $baseDir . '/src/ConfigurationException/InvalidConfigurationException.php',
  2739. 'PhpCsFixer\\ConfigurationException\\InvalidFixerConfigurationException' => $baseDir . '/src/ConfigurationException/InvalidFixerConfigurationException.php',
  2740. 'PhpCsFixer\\ConfigurationException\\InvalidForEnvFixerConfigurationException' => $baseDir . '/src/ConfigurationException/InvalidForEnvFixerConfigurationException.php',
  2741. 'PhpCsFixer\\ConfigurationException\\RequiredFixerConfigurationException' => $baseDir . '/src/ConfigurationException/RequiredFixerConfigurationException.php',
  2742. 'PhpCsFixer\\Console\\Application' => $baseDir . '/src/Console/Application.php',
  2743. 'PhpCsFixer\\Console\\Command\\CheckCommand' => $baseDir . '/src/Console/Command/CheckCommand.php',
  2744. 'PhpCsFixer\\Console\\Command\\DescribeCommand' => $baseDir . '/src/Console/Command/DescribeCommand.php',
  2745. 'PhpCsFixer\\Console\\Command\\DescribeNameNotFoundException' => $baseDir . '/src/Console/Command/DescribeNameNotFoundException.php',
  2746. 'PhpCsFixer\\Console\\Command\\DocumentationCommand' => $baseDir . '/src/Console/Command/DocumentationCommand.php',
  2747. 'PhpCsFixer\\Console\\Command\\FixCommand' => $baseDir . '/src/Console/Command/FixCommand.php',
  2748. 'PhpCsFixer\\Console\\Command\\FixCommandExitStatusCalculator' => $baseDir . '/src/Console/Command/FixCommandExitStatusCalculator.php',
  2749. 'PhpCsFixer\\Console\\Command\\HelpCommand' => $baseDir . '/src/Console/Command/HelpCommand.php',
  2750. 'PhpCsFixer\\Console\\Command\\ListFilesCommand' => $baseDir . '/src/Console/Command/ListFilesCommand.php',
  2751. 'PhpCsFixer\\Console\\Command\\ListSetsCommand' => $baseDir . '/src/Console/Command/ListSetsCommand.php',
  2752. 'PhpCsFixer\\Console\\Command\\SelfUpdateCommand' => $baseDir . '/src/Console/Command/SelfUpdateCommand.php',
  2753. 'PhpCsFixer\\Console\\Command\\WorkerCommand' => $baseDir . '/src/Console/Command/WorkerCommand.php',
  2754. 'PhpCsFixer\\Console\\ConfigurationResolver' => $baseDir . '/src/Console/ConfigurationResolver.php',
  2755. 'PhpCsFixer\\Console\\Output\\ErrorOutput' => $baseDir . '/src/Console/Output/ErrorOutput.php',
  2756. 'PhpCsFixer\\Console\\Output\\OutputContext' => $baseDir . '/src/Console/Output/OutputContext.php',
  2757. 'PhpCsFixer\\Console\\Output\\Progress\\DotsOutput' => $baseDir . '/src/Console/Output/Progress/DotsOutput.php',
  2758. 'PhpCsFixer\\Console\\Output\\Progress\\NullOutput' => $baseDir . '/src/Console/Output/Progress/NullOutput.php',
  2759. 'PhpCsFixer\\Console\\Output\\Progress\\PercentageBarOutput' => $baseDir . '/src/Console/Output/Progress/PercentageBarOutput.php',
  2760. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputFactory' => $baseDir . '/src/Console/Output/Progress/ProgressOutputFactory.php',
  2761. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputInterface' => $baseDir . '/src/Console/Output/Progress/ProgressOutputInterface.php',
  2762. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputType' => $baseDir . '/src/Console/Output/Progress/ProgressOutputType.php',
  2763. 'PhpCsFixer\\Console\\Report\\FixReport\\CheckstyleReporter' => $baseDir . '/src/Console/Report/FixReport/CheckstyleReporter.php',
  2764. 'PhpCsFixer\\Console\\Report\\FixReport\\GitlabReporter' => $baseDir . '/src/Console/Report/FixReport/GitlabReporter.php',
  2765. 'PhpCsFixer\\Console\\Report\\FixReport\\JsonReporter' => $baseDir . '/src/Console/Report/FixReport/JsonReporter.php',
  2766. 'PhpCsFixer\\Console\\Report\\FixReport\\JunitReporter' => $baseDir . '/src/Console/Report/FixReport/JunitReporter.php',
  2767. 'PhpCsFixer\\Console\\Report\\FixReport\\ReportSummary' => $baseDir . '/src/Console/Report/FixReport/ReportSummary.php',
  2768. 'PhpCsFixer\\Console\\Report\\FixReport\\ReporterFactory' => $baseDir . '/src/Console/Report/FixReport/ReporterFactory.php',
  2769. 'PhpCsFixer\\Console\\Report\\FixReport\\ReporterInterface' => $baseDir . '/src/Console/Report/FixReport/ReporterInterface.php',
  2770. 'PhpCsFixer\\Console\\Report\\FixReport\\TextReporter' => $baseDir . '/src/Console/Report/FixReport/TextReporter.php',
  2771. 'PhpCsFixer\\Console\\Report\\FixReport\\XmlReporter' => $baseDir . '/src/Console/Report/FixReport/XmlReporter.php',
  2772. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\JsonReporter' => $baseDir . '/src/Console/Report/ListSetsReport/JsonReporter.php',
  2773. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReportSummary' => $baseDir . '/src/Console/Report/ListSetsReport/ReportSummary.php',
  2774. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReporterFactory' => $baseDir . '/src/Console/Report/ListSetsReport/ReporterFactory.php',
  2775. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReporterInterface' => $baseDir . '/src/Console/Report/ListSetsReport/ReporterInterface.php',
  2776. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\TextReporter' => $baseDir . '/src/Console/Report/ListSetsReport/TextReporter.php',
  2777. 'PhpCsFixer\\Console\\SelfUpdate\\GithubClient' => $baseDir . '/src/Console/SelfUpdate/GithubClient.php',
  2778. 'PhpCsFixer\\Console\\SelfUpdate\\GithubClientInterface' => $baseDir . '/src/Console/SelfUpdate/GithubClientInterface.php',
  2779. 'PhpCsFixer\\Console\\SelfUpdate\\NewVersionChecker' => $baseDir . '/src/Console/SelfUpdate/NewVersionChecker.php',
  2780. 'PhpCsFixer\\Console\\SelfUpdate\\NewVersionCheckerInterface' => $baseDir . '/src/Console/SelfUpdate/NewVersionCheckerInterface.php',
  2781. 'PhpCsFixer\\Console\\WarningsDetector' => $baseDir . '/src/Console/WarningsDetector.php',
  2782. 'PhpCsFixer\\Differ\\DiffConsoleFormatter' => $baseDir . '/src/Differ/DiffConsoleFormatter.php',
  2783. 'PhpCsFixer\\Differ\\DifferInterface' => $baseDir . '/src/Differ/DifferInterface.php',
  2784. 'PhpCsFixer\\Differ\\FullDiffer' => $baseDir . '/src/Differ/FullDiffer.php',
  2785. 'PhpCsFixer\\Differ\\NullDiffer' => $baseDir . '/src/Differ/NullDiffer.php',
  2786. 'PhpCsFixer\\Differ\\UnifiedDiffer' => $baseDir . '/src/Differ/UnifiedDiffer.php',
  2787. 'PhpCsFixer\\DocBlock\\Annotation' => $baseDir . '/src/DocBlock/Annotation.php',
  2788. 'PhpCsFixer\\DocBlock\\DocBlock' => $baseDir . '/src/DocBlock/DocBlock.php',
  2789. 'PhpCsFixer\\DocBlock\\Line' => $baseDir . '/src/DocBlock/Line.php',
  2790. 'PhpCsFixer\\DocBlock\\ShortDescription' => $baseDir . '/src/DocBlock/ShortDescription.php',
  2791. 'PhpCsFixer\\DocBlock\\Tag' => $baseDir . '/src/DocBlock/Tag.php',
  2792. 'PhpCsFixer\\DocBlock\\TagComparator' => $baseDir . '/src/DocBlock/TagComparator.php',
  2793. 'PhpCsFixer\\DocBlock\\TypeExpression' => $baseDir . '/src/DocBlock/TypeExpression.php',
  2794. 'PhpCsFixer\\Doctrine\\Annotation\\DocLexer' => $baseDir . '/src/Doctrine/Annotation/DocLexer.php',
  2795. 'PhpCsFixer\\Doctrine\\Annotation\\Token' => $baseDir . '/src/Doctrine/Annotation/Token.php',
  2796. 'PhpCsFixer\\Doctrine\\Annotation\\Tokens' => $baseDir . '/src/Doctrine/Annotation/Tokens.php',
  2797. 'PhpCsFixer\\Documentation\\DocumentationLocator' => $baseDir . '/src/Documentation/DocumentationLocator.php',
  2798. 'PhpCsFixer\\Documentation\\FixerDocumentGenerator' => $baseDir . '/src/Documentation/FixerDocumentGenerator.php',
  2799. 'PhpCsFixer\\Documentation\\RstUtils' => $baseDir . '/src/Documentation/RstUtils.php',
  2800. 'PhpCsFixer\\Documentation\\RuleSetDocumentationGenerator' => $baseDir . '/src/Documentation/RuleSetDocumentationGenerator.php',
  2801. 'PhpCsFixer\\Error\\Error' => $baseDir . '/src/Error/Error.php',
  2802. 'PhpCsFixer\\Error\\ErrorsManager' => $baseDir . '/src/Error/ErrorsManager.php',
  2803. 'PhpCsFixer\\Error\\SourceExceptionFactory' => $baseDir . '/src/Error/SourceExceptionFactory.php',
  2804. 'PhpCsFixer\\ExecutorWithoutErrorHandler' => $baseDir . '/src/ExecutorWithoutErrorHandler.php',
  2805. 'PhpCsFixer\\ExecutorWithoutErrorHandlerException' => $baseDir . '/src/ExecutorWithoutErrorHandlerException.php',
  2806. 'PhpCsFixer\\FileReader' => $baseDir . '/src/FileReader.php',
  2807. 'PhpCsFixer\\FileRemoval' => $baseDir . '/src/FileRemoval.php',
  2808. 'PhpCsFixer\\Finder' => $baseDir . '/src/Finder.php',
  2809. 'PhpCsFixer\\FixerConfiguration\\AliasedFixerOption' => $baseDir . '/src/FixerConfiguration/AliasedFixerOption.php',
  2810. 'PhpCsFixer\\FixerConfiguration\\AliasedFixerOptionBuilder' => $baseDir . '/src/FixerConfiguration/AliasedFixerOptionBuilder.php',
  2811. 'PhpCsFixer\\FixerConfiguration\\AllowedValueSubset' => $baseDir . '/src/FixerConfiguration/AllowedValueSubset.php',
  2812. 'PhpCsFixer\\FixerConfiguration\\DeprecatedFixerOption' => $baseDir . '/src/FixerConfiguration/DeprecatedFixerOption.php',
  2813. 'PhpCsFixer\\FixerConfiguration\\DeprecatedFixerOptionInterface' => $baseDir . '/src/FixerConfiguration/DeprecatedFixerOptionInterface.php',
  2814. 'PhpCsFixer\\FixerConfiguration\\FixerConfigurationResolver' => $baseDir . '/src/FixerConfiguration/FixerConfigurationResolver.php',
  2815. 'PhpCsFixer\\FixerConfiguration\\FixerConfigurationResolverInterface' => $baseDir . '/src/FixerConfiguration/FixerConfigurationResolverInterface.php',
  2816. 'PhpCsFixer\\FixerConfiguration\\FixerOption' => $baseDir . '/src/FixerConfiguration/FixerOption.php',
  2817. 'PhpCsFixer\\FixerConfiguration\\FixerOptionBuilder' => $baseDir . '/src/FixerConfiguration/FixerOptionBuilder.php',
  2818. 'PhpCsFixer\\FixerConfiguration\\FixerOptionInterface' => $baseDir . '/src/FixerConfiguration/FixerOptionInterface.php',
  2819. 'PhpCsFixer\\FixerConfiguration\\FixerOptionSorter' => $baseDir . '/src/FixerConfiguration/FixerOptionSorter.php',
  2820. 'PhpCsFixer\\FixerConfiguration\\InvalidOptionsForEnvException' => $baseDir . '/src/FixerConfiguration/InvalidOptionsForEnvException.php',
  2821. 'PhpCsFixer\\FixerDefinition\\CodeSample' => $baseDir . '/src/FixerDefinition/CodeSample.php',
  2822. 'PhpCsFixer\\FixerDefinition\\CodeSampleInterface' => $baseDir . '/src/FixerDefinition/CodeSampleInterface.php',
  2823. 'PhpCsFixer\\FixerDefinition\\FileSpecificCodeSample' => $baseDir . '/src/FixerDefinition/FileSpecificCodeSample.php',
  2824. 'PhpCsFixer\\FixerDefinition\\FileSpecificCodeSampleInterface' => $baseDir . '/src/FixerDefinition/FileSpecificCodeSampleInterface.php',
  2825. 'PhpCsFixer\\FixerDefinition\\FixerDefinition' => $baseDir . '/src/FixerDefinition/FixerDefinition.php',
  2826. 'PhpCsFixer\\FixerDefinition\\FixerDefinitionInterface' => $baseDir . '/src/FixerDefinition/FixerDefinitionInterface.php',
  2827. 'PhpCsFixer\\FixerDefinition\\VersionSpecificCodeSample' => $baseDir . '/src/FixerDefinition/VersionSpecificCodeSample.php',
  2828. 'PhpCsFixer\\FixerDefinition\\VersionSpecificCodeSampleInterface' => $baseDir . '/src/FixerDefinition/VersionSpecificCodeSampleInterface.php',
  2829. 'PhpCsFixer\\FixerDefinition\\VersionSpecification' => $baseDir . '/src/FixerDefinition/VersionSpecification.php',
  2830. 'PhpCsFixer\\FixerDefinition\\VersionSpecificationInterface' => $baseDir . '/src/FixerDefinition/VersionSpecificationInterface.php',
  2831. 'PhpCsFixer\\FixerFactory' => $baseDir . '/src/FixerFactory.php',
  2832. 'PhpCsFixer\\FixerNameValidator' => $baseDir . '/src/FixerNameValidator.php',
  2833. 'PhpCsFixer\\Fixer\\AbstractIncrementOperatorFixer' => $baseDir . '/src/Fixer/AbstractIncrementOperatorFixer.php',
  2834. 'PhpCsFixer\\Fixer\\AbstractPhpUnitFixer' => $baseDir . '/src/Fixer/AbstractPhpUnitFixer.php',
  2835. 'PhpCsFixer\\Fixer\\AbstractShortOperatorFixer' => $baseDir . '/src/Fixer/AbstractShortOperatorFixer.php',
  2836. 'PhpCsFixer\\Fixer\\Alias\\ArrayPushFixer' => $baseDir . '/src/Fixer/Alias/ArrayPushFixer.php',
  2837. 'PhpCsFixer\\Fixer\\Alias\\BacktickToShellExecFixer' => $baseDir . '/src/Fixer/Alias/BacktickToShellExecFixer.php',
  2838. 'PhpCsFixer\\Fixer\\Alias\\EregToPregFixer' => $baseDir . '/src/Fixer/Alias/EregToPregFixer.php',
  2839. 'PhpCsFixer\\Fixer\\Alias\\MbStrFunctionsFixer' => $baseDir . '/src/Fixer/Alias/MbStrFunctionsFixer.php',
  2840. 'PhpCsFixer\\Fixer\\Alias\\ModernizeStrposFixer' => $baseDir . '/src/Fixer/Alias/ModernizeStrposFixer.php',
  2841. 'PhpCsFixer\\Fixer\\Alias\\NoAliasFunctionsFixer' => $baseDir . '/src/Fixer/Alias/NoAliasFunctionsFixer.php',
  2842. 'PhpCsFixer\\Fixer\\Alias\\NoAliasLanguageConstructCallFixer' => $baseDir . '/src/Fixer/Alias/NoAliasLanguageConstructCallFixer.php',
  2843. 'PhpCsFixer\\Fixer\\Alias\\NoMixedEchoPrintFixer' => $baseDir . '/src/Fixer/Alias/NoMixedEchoPrintFixer.php',
  2844. 'PhpCsFixer\\Fixer\\Alias\\PowToExponentiationFixer' => $baseDir . '/src/Fixer/Alias/PowToExponentiationFixer.php',
  2845. 'PhpCsFixer\\Fixer\\Alias\\RandomApiMigrationFixer' => $baseDir . '/src/Fixer/Alias/RandomApiMigrationFixer.php',
  2846. 'PhpCsFixer\\Fixer\\Alias\\SetTypeToCastFixer' => $baseDir . '/src/Fixer/Alias/SetTypeToCastFixer.php',
  2847. 'PhpCsFixer\\Fixer\\ArrayNotation\\ArraySyntaxFixer' => $baseDir . '/src/Fixer/ArrayNotation/ArraySyntaxFixer.php',
  2848. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoMultilineWhitespaceAroundDoubleArrowFixer' => $baseDir . '/src/Fixer/ArrayNotation/NoMultilineWhitespaceAroundDoubleArrowFixer.php',
  2849. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoTrailingCommaInSinglelineArrayFixer' => $baseDir . '/src/Fixer/ArrayNotation/NoTrailingCommaInSinglelineArrayFixer.php',
  2850. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoWhitespaceBeforeCommaInArrayFixer' => $baseDir . '/src/Fixer/ArrayNotation/NoWhitespaceBeforeCommaInArrayFixer.php',
  2851. 'PhpCsFixer\\Fixer\\ArrayNotation\\NormalizeIndexBraceFixer' => $baseDir . '/src/Fixer/ArrayNotation/NormalizeIndexBraceFixer.php',
  2852. 'PhpCsFixer\\Fixer\\ArrayNotation\\ReturnToYieldFromFixer' => $baseDir . '/src/Fixer/ArrayNotation/ReturnToYieldFromFixer.php',
  2853. 'PhpCsFixer\\Fixer\\ArrayNotation\\TrimArraySpacesFixer' => $baseDir . '/src/Fixer/ArrayNotation/TrimArraySpacesFixer.php',
  2854. 'PhpCsFixer\\Fixer\\ArrayNotation\\WhitespaceAfterCommaInArrayFixer' => $baseDir . '/src/Fixer/ArrayNotation/WhitespaceAfterCommaInArrayFixer.php',
  2855. 'PhpCsFixer\\Fixer\\ArrayNotation\\YieldFromArrayToYieldsFixer' => $baseDir . '/src/Fixer/ArrayNotation/YieldFromArrayToYieldsFixer.php',
  2856. 'PhpCsFixer\\Fixer\\AttributeNotation\\AttributeEmptyParenthesesFixer' => $baseDir . '/src/Fixer/AttributeNotation/AttributeEmptyParenthesesFixer.php',
  2857. 'PhpCsFixer\\Fixer\\AttributeNotation\\GeneralAttributeRemoveFixer' => $baseDir . '/src/Fixer/AttributeNotation/GeneralAttributeRemoveFixer.php',
  2858. 'PhpCsFixer\\Fixer\\AttributeNotation\\OrderedAttributesFixer' => $baseDir . '/src/Fixer/AttributeNotation/OrderedAttributesFixer.php',
  2859. 'PhpCsFixer\\Fixer\\Basic\\BracesFixer' => $baseDir . '/src/Fixer/Basic/BracesFixer.php',
  2860. 'PhpCsFixer\\Fixer\\Basic\\BracesPositionFixer' => $baseDir . '/src/Fixer/Basic/BracesPositionFixer.php',
  2861. 'PhpCsFixer\\Fixer\\Basic\\CurlyBracesPositionFixer' => $baseDir . '/src/Fixer/Basic/CurlyBracesPositionFixer.php',
  2862. 'PhpCsFixer\\Fixer\\Basic\\EncodingFixer' => $baseDir . '/src/Fixer/Basic/EncodingFixer.php',
  2863. 'PhpCsFixer\\Fixer\\Basic\\NoMultipleStatementsPerLineFixer' => $baseDir . '/src/Fixer/Basic/NoMultipleStatementsPerLineFixer.php',
  2864. 'PhpCsFixer\\Fixer\\Basic\\NoTrailingCommaInSinglelineFixer' => $baseDir . '/src/Fixer/Basic/NoTrailingCommaInSinglelineFixer.php',
  2865. 'PhpCsFixer\\Fixer\\Basic\\NonPrintableCharacterFixer' => $baseDir . '/src/Fixer/Basic/NonPrintableCharacterFixer.php',
  2866. 'PhpCsFixer\\Fixer\\Basic\\NumericLiteralSeparatorFixer' => $baseDir . '/src/Fixer/Basic/NumericLiteralSeparatorFixer.php',
  2867. 'PhpCsFixer\\Fixer\\Basic\\OctalNotationFixer' => $baseDir . '/src/Fixer/Basic/OctalNotationFixer.php',
  2868. 'PhpCsFixer\\Fixer\\Basic\\PsrAutoloadingFixer' => $baseDir . '/src/Fixer/Basic/PsrAutoloadingFixer.php',
  2869. 'PhpCsFixer\\Fixer\\Basic\\SingleLineEmptyBodyFixer' => $baseDir . '/src/Fixer/Basic/SingleLineEmptyBodyFixer.php',
  2870. 'PhpCsFixer\\Fixer\\Casing\\ClassReferenceNameCasingFixer' => $baseDir . '/src/Fixer/Casing/ClassReferenceNameCasingFixer.php',
  2871. 'PhpCsFixer\\Fixer\\Casing\\ConstantCaseFixer' => $baseDir . '/src/Fixer/Casing/ConstantCaseFixer.php',
  2872. 'PhpCsFixer\\Fixer\\Casing\\IntegerLiteralCaseFixer' => $baseDir . '/src/Fixer/Casing/IntegerLiteralCaseFixer.php',
  2873. 'PhpCsFixer\\Fixer\\Casing\\LowercaseKeywordsFixer' => $baseDir . '/src/Fixer/Casing/LowercaseKeywordsFixer.php',
  2874. 'PhpCsFixer\\Fixer\\Casing\\LowercaseStaticReferenceFixer' => $baseDir . '/src/Fixer/Casing/LowercaseStaticReferenceFixer.php',
  2875. 'PhpCsFixer\\Fixer\\Casing\\MagicConstantCasingFixer' => $baseDir . '/src/Fixer/Casing/MagicConstantCasingFixer.php',
  2876. 'PhpCsFixer\\Fixer\\Casing\\MagicMethodCasingFixer' => $baseDir . '/src/Fixer/Casing/MagicMethodCasingFixer.php',
  2877. 'PhpCsFixer\\Fixer\\Casing\\NativeFunctionCasingFixer' => $baseDir . '/src/Fixer/Casing/NativeFunctionCasingFixer.php',
  2878. 'PhpCsFixer\\Fixer\\Casing\\NativeFunctionTypeDeclarationCasingFixer' => $baseDir . '/src/Fixer/Casing/NativeFunctionTypeDeclarationCasingFixer.php',
  2879. 'PhpCsFixer\\Fixer\\Casing\\NativeTypeDeclarationCasingFixer' => $baseDir . '/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php',
  2880. 'PhpCsFixer\\Fixer\\CastNotation\\CastSpacesFixer' => $baseDir . '/src/Fixer/CastNotation/CastSpacesFixer.php',
  2881. 'PhpCsFixer\\Fixer\\CastNotation\\LowercaseCastFixer' => $baseDir . '/src/Fixer/CastNotation/LowercaseCastFixer.php',
  2882. 'PhpCsFixer\\Fixer\\CastNotation\\ModernizeTypesCastingFixer' => $baseDir . '/src/Fixer/CastNotation/ModernizeTypesCastingFixer.php',
  2883. 'PhpCsFixer\\Fixer\\CastNotation\\NoShortBoolCastFixer' => $baseDir . '/src/Fixer/CastNotation/NoShortBoolCastFixer.php',
  2884. 'PhpCsFixer\\Fixer\\CastNotation\\NoUnsetCastFixer' => $baseDir . '/src/Fixer/CastNotation/NoUnsetCastFixer.php',
  2885. 'PhpCsFixer\\Fixer\\CastNotation\\ShortScalarCastFixer' => $baseDir . '/src/Fixer/CastNotation/ShortScalarCastFixer.php',
  2886. 'PhpCsFixer\\Fixer\\ClassNotation\\ClassAttributesSeparationFixer' => $baseDir . '/src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php',
  2887. 'PhpCsFixer\\Fixer\\ClassNotation\\ClassDefinitionFixer' => $baseDir . '/src/Fixer/ClassNotation/ClassDefinitionFixer.php',
  2888. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalClassFixer' => $baseDir . '/src/Fixer/ClassNotation/FinalClassFixer.php',
  2889. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalInternalClassFixer' => $baseDir . '/src/Fixer/ClassNotation/FinalInternalClassFixer.php',
  2890. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalPublicMethodForAbstractClassFixer' => $baseDir . '/src/Fixer/ClassNotation/FinalPublicMethodForAbstractClassFixer.php',
  2891. 'PhpCsFixer\\Fixer\\ClassNotation\\NoBlankLinesAfterClassOpeningFixer' => $baseDir . '/src/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixer.php',
  2892. 'PhpCsFixer\\Fixer\\ClassNotation\\NoNullPropertyInitializationFixer' => $baseDir . '/src/Fixer/ClassNotation/NoNullPropertyInitializationFixer.php',
  2893. 'PhpCsFixer\\Fixer\\ClassNotation\\NoPhp4ConstructorFixer' => $baseDir . '/src/Fixer/ClassNotation/NoPhp4ConstructorFixer.php',
  2894. 'PhpCsFixer\\Fixer\\ClassNotation\\NoUnneededFinalMethodFixer' => $baseDir . '/src/Fixer/ClassNotation/NoUnneededFinalMethodFixer.php',
  2895. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedClassElementsFixer' => $baseDir . '/src/Fixer/ClassNotation/OrderedClassElementsFixer.php',
  2896. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedInterfacesFixer' => $baseDir . '/src/Fixer/ClassNotation/OrderedInterfacesFixer.php',
  2897. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedTraitsFixer' => $baseDir . '/src/Fixer/ClassNotation/OrderedTraitsFixer.php',
  2898. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedTypesFixer' => $baseDir . '/src/Fixer/ClassNotation/OrderedTypesFixer.php',
  2899. 'PhpCsFixer\\Fixer\\ClassNotation\\PhpdocReadonlyClassCommentToKeywordFixer' => $baseDir . '/src/Fixer/ClassNotation/PhpdocReadonlyClassCommentToKeywordFixer.php',
  2900. 'PhpCsFixer\\Fixer\\ClassNotation\\ProtectedToPrivateFixer' => $baseDir . '/src/Fixer/ClassNotation/ProtectedToPrivateFixer.php',
  2901. 'PhpCsFixer\\Fixer\\ClassNotation\\SelfAccessorFixer' => $baseDir . '/src/Fixer/ClassNotation/SelfAccessorFixer.php',
  2902. 'PhpCsFixer\\Fixer\\ClassNotation\\SelfStaticAccessorFixer' => $baseDir . '/src/Fixer/ClassNotation/SelfStaticAccessorFixer.php',
  2903. 'PhpCsFixer\\Fixer\\ClassNotation\\SingleClassElementPerStatementFixer' => $baseDir . '/src/Fixer/ClassNotation/SingleClassElementPerStatementFixer.php',
  2904. 'PhpCsFixer\\Fixer\\ClassNotation\\SingleTraitInsertPerStatementFixer' => $baseDir . '/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php',
  2905. 'PhpCsFixer\\Fixer\\ClassNotation\\StaticPrivateMethodFixer' => $baseDir . '/src/Fixer/ClassNotation/StaticPrivateMethodFixer.php',
  2906. 'PhpCsFixer\\Fixer\\ClassNotation\\VisibilityRequiredFixer' => $baseDir . '/src/Fixer/ClassNotation/VisibilityRequiredFixer.php',
  2907. 'PhpCsFixer\\Fixer\\ClassUsage\\DateTimeImmutableFixer' => $baseDir . '/src/Fixer/ClassUsage/DateTimeImmutableFixer.php',
  2908. 'PhpCsFixer\\Fixer\\Comment\\CommentToPhpdocFixer' => $baseDir . '/src/Fixer/Comment/CommentToPhpdocFixer.php',
  2909. 'PhpCsFixer\\Fixer\\Comment\\HeaderCommentFixer' => $baseDir . '/src/Fixer/Comment/HeaderCommentFixer.php',
  2910. 'PhpCsFixer\\Fixer\\Comment\\MultilineCommentOpeningClosingFixer' => $baseDir . '/src/Fixer/Comment/MultilineCommentOpeningClosingFixer.php',
  2911. 'PhpCsFixer\\Fixer\\Comment\\NoEmptyCommentFixer' => $baseDir . '/src/Fixer/Comment/NoEmptyCommentFixer.php',
  2912. 'PhpCsFixer\\Fixer\\Comment\\NoTrailingWhitespaceInCommentFixer' => $baseDir . '/src/Fixer/Comment/NoTrailingWhitespaceInCommentFixer.php',
  2913. 'PhpCsFixer\\Fixer\\Comment\\SingleLineCommentSpacingFixer' => $baseDir . '/src/Fixer/Comment/SingleLineCommentSpacingFixer.php',
  2914. 'PhpCsFixer\\Fixer\\Comment\\SingleLineCommentStyleFixer' => $baseDir . '/src/Fixer/Comment/SingleLineCommentStyleFixer.php',
  2915. 'PhpCsFixer\\Fixer\\ConfigurableFixerInterface' => $baseDir . '/src/Fixer/ConfigurableFixerInterface.php',
  2916. 'PhpCsFixer\\Fixer\\ConfigurableFixerTrait' => $baseDir . '/src/Fixer/ConfigurableFixerTrait.php',
  2917. 'PhpCsFixer\\Fixer\\ConstantNotation\\NativeConstantInvocationFixer' => $baseDir . '/src/Fixer/ConstantNotation/NativeConstantInvocationFixer.php',
  2918. 'PhpCsFixer\\Fixer\\ControlStructure\\ControlStructureBracesFixer' => $baseDir . '/src/Fixer/ControlStructure/ControlStructureBracesFixer.php',
  2919. 'PhpCsFixer\\Fixer\\ControlStructure\\ControlStructureContinuationPositionFixer' => $baseDir . '/src/Fixer/ControlStructure/ControlStructureContinuationPositionFixer.php',
  2920. 'PhpCsFixer\\Fixer\\ControlStructure\\ElseifFixer' => $baseDir . '/src/Fixer/ControlStructure/ElseifFixer.php',
  2921. 'PhpCsFixer\\Fixer\\ControlStructure\\EmptyLoopBodyFixer' => $baseDir . '/src/Fixer/ControlStructure/EmptyLoopBodyFixer.php',
  2922. 'PhpCsFixer\\Fixer\\ControlStructure\\EmptyLoopConditionFixer' => $baseDir . '/src/Fixer/ControlStructure/EmptyLoopConditionFixer.php',
  2923. 'PhpCsFixer\\Fixer\\ControlStructure\\IncludeFixer' => $baseDir . '/src/Fixer/ControlStructure/IncludeFixer.php',
  2924. 'PhpCsFixer\\Fixer\\ControlStructure\\NoAlternativeSyntaxFixer' => $baseDir . '/src/Fixer/ControlStructure/NoAlternativeSyntaxFixer.php',
  2925. 'PhpCsFixer\\Fixer\\ControlStructure\\NoBreakCommentFixer' => $baseDir . '/src/Fixer/ControlStructure/NoBreakCommentFixer.php',
  2926. 'PhpCsFixer\\Fixer\\ControlStructure\\NoSuperfluousElseifFixer' => $baseDir . '/src/Fixer/ControlStructure/NoSuperfluousElseifFixer.php',
  2927. 'PhpCsFixer\\Fixer\\ControlStructure\\NoTrailingCommaInListCallFixer' => $baseDir . '/src/Fixer/ControlStructure/NoTrailingCommaInListCallFixer.php',
  2928. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededBracesFixer' => $baseDir . '/src/Fixer/ControlStructure/NoUnneededBracesFixer.php',
  2929. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededControlParenthesesFixer' => $baseDir . '/src/Fixer/ControlStructure/NoUnneededControlParenthesesFixer.php',
  2930. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededCurlyBracesFixer' => $baseDir . '/src/Fixer/ControlStructure/NoUnneededCurlyBracesFixer.php',
  2931. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUselessElseFixer' => $baseDir . '/src/Fixer/ControlStructure/NoUselessElseFixer.php',
  2932. 'PhpCsFixer\\Fixer\\ControlStructure\\SimplifiedIfReturnFixer' => $baseDir . '/src/Fixer/ControlStructure/SimplifiedIfReturnFixer.php',
  2933. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchCaseSemicolonToColonFixer' => $baseDir . '/src/Fixer/ControlStructure/SwitchCaseSemicolonToColonFixer.php',
  2934. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchCaseSpaceFixer' => $baseDir . '/src/Fixer/ControlStructure/SwitchCaseSpaceFixer.php',
  2935. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchContinueToBreakFixer' => $baseDir . '/src/Fixer/ControlStructure/SwitchContinueToBreakFixer.php',
  2936. 'PhpCsFixer\\Fixer\\ControlStructure\\TrailingCommaInMultilineFixer' => $baseDir . '/src/Fixer/ControlStructure/TrailingCommaInMultilineFixer.php',
  2937. 'PhpCsFixer\\Fixer\\ControlStructure\\YodaStyleFixer' => $baseDir . '/src/Fixer/ControlStructure/YodaStyleFixer.php',
  2938. 'PhpCsFixer\\Fixer\\DeprecatedFixerInterface' => $baseDir . '/src/Fixer/DeprecatedFixerInterface.php',
  2939. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationArrayAssignmentFixer' => $baseDir . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationArrayAssignmentFixer.php',
  2940. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationBracesFixer' => $baseDir . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixer.php',
  2941. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationIndentationFixer' => $baseDir . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationIndentationFixer.php',
  2942. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationSpacesFixer' => $baseDir . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationSpacesFixer.php',
  2943. 'PhpCsFixer\\Fixer\\ExperimentalFixerInterface' => $baseDir . '/src/Fixer/ExperimentalFixerInterface.php',
  2944. 'PhpCsFixer\\Fixer\\FixerInterface' => $baseDir . '/src/Fixer/FixerInterface.php',
  2945. 'PhpCsFixer\\Fixer\\FunctionNotation\\CombineNestedDirnameFixer' => $baseDir . '/src/Fixer/FunctionNotation/CombineNestedDirnameFixer.php',
  2946. 'PhpCsFixer\\Fixer\\FunctionNotation\\DateTimeCreateFromFormatCallFixer' => $baseDir . '/src/Fixer/FunctionNotation/DateTimeCreateFromFormatCallFixer.php',
  2947. 'PhpCsFixer\\Fixer\\FunctionNotation\\FopenFlagOrderFixer' => $baseDir . '/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php',
  2948. 'PhpCsFixer\\Fixer\\FunctionNotation\\FopenFlagsFixer' => $baseDir . '/src/Fixer/FunctionNotation/FopenFlagsFixer.php',
  2949. 'PhpCsFixer\\Fixer\\FunctionNotation\\FunctionDeclarationFixer' => $baseDir . '/src/Fixer/FunctionNotation/FunctionDeclarationFixer.php',
  2950. 'PhpCsFixer\\Fixer\\FunctionNotation\\FunctionTypehintSpaceFixer' => $baseDir . '/src/Fixer/FunctionNotation/FunctionTypehintSpaceFixer.php',
  2951. 'PhpCsFixer\\Fixer\\FunctionNotation\\ImplodeCallFixer' => $baseDir . '/src/Fixer/FunctionNotation/ImplodeCallFixer.php',
  2952. 'PhpCsFixer\\Fixer\\FunctionNotation\\LambdaNotUsedImportFixer' => $baseDir . '/src/Fixer/FunctionNotation/LambdaNotUsedImportFixer.php',
  2953. 'PhpCsFixer\\Fixer\\FunctionNotation\\MethodArgumentSpaceFixer' => $baseDir . '/src/Fixer/FunctionNotation/MethodArgumentSpaceFixer.php',
  2954. 'PhpCsFixer\\Fixer\\FunctionNotation\\MultilinePromotedPropertiesFixer' => $baseDir . '/src/Fixer/FunctionNotation/MultilinePromotedPropertiesFixer.php',
  2955. 'PhpCsFixer\\Fixer\\FunctionNotation\\NativeFunctionInvocationFixer' => $baseDir . '/src/Fixer/FunctionNotation/NativeFunctionInvocationFixer.php',
  2956. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoSpacesAfterFunctionNameFixer' => $baseDir . '/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php',
  2957. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoTrailingCommaInSinglelineFunctionCallFixer' => $baseDir . '/src/Fixer/FunctionNotation/NoTrailingCommaInSinglelineFunctionCallFixer.php',
  2958. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoUnreachableDefaultArgumentValueFixer' => $baseDir . '/src/Fixer/FunctionNotation/NoUnreachableDefaultArgumentValueFixer.php',
  2959. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoUselessSprintfFixer' => $baseDir . '/src/Fixer/FunctionNotation/NoUselessSprintfFixer.php',
  2960. 'PhpCsFixer\\Fixer\\FunctionNotation\\NullableTypeDeclarationForDefaultNullValueFixer' => $baseDir . '/src/Fixer/FunctionNotation/NullableTypeDeclarationForDefaultNullValueFixer.php',
  2961. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToParamTypeFixer' => $baseDir . '/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php',
  2962. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToPropertyTypeFixer' => $baseDir . '/src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php',
  2963. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToReturnTypeFixer' => $baseDir . '/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php',
  2964. 'PhpCsFixer\\Fixer\\FunctionNotation\\RegularCallableCallFixer' => $baseDir . '/src/Fixer/FunctionNotation/RegularCallableCallFixer.php',
  2965. 'PhpCsFixer\\Fixer\\FunctionNotation\\ReturnTypeDeclarationFixer' => $baseDir . '/src/Fixer/FunctionNotation/ReturnTypeDeclarationFixer.php',
  2966. 'PhpCsFixer\\Fixer\\FunctionNotation\\SingleLineThrowFixer' => $baseDir . '/src/Fixer/FunctionNotation/SingleLineThrowFixer.php',
  2967. 'PhpCsFixer\\Fixer\\FunctionNotation\\StaticLambdaFixer' => $baseDir . '/src/Fixer/FunctionNotation/StaticLambdaFixer.php',
  2968. 'PhpCsFixer\\Fixer\\FunctionNotation\\UseArrowFunctionsFixer' => $baseDir . '/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php',
  2969. 'PhpCsFixer\\Fixer\\FunctionNotation\\VoidReturnFixer' => $baseDir . '/src/Fixer/FunctionNotation/VoidReturnFixer.php',
  2970. 'PhpCsFixer\\Fixer\\Import\\FullyQualifiedStrictTypesFixer' => $baseDir . '/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php',
  2971. 'PhpCsFixer\\Fixer\\Import\\GlobalNamespaceImportFixer' => $baseDir . '/src/Fixer/Import/GlobalNamespaceImportFixer.php',
  2972. 'PhpCsFixer\\Fixer\\Import\\GroupImportFixer' => $baseDir . '/src/Fixer/Import/GroupImportFixer.php',
  2973. 'PhpCsFixer\\Fixer\\Import\\NoLeadingImportSlashFixer' => $baseDir . '/src/Fixer/Import/NoLeadingImportSlashFixer.php',
  2974. 'PhpCsFixer\\Fixer\\Import\\NoUnneededImportAliasFixer' => $baseDir . '/src/Fixer/Import/NoUnneededImportAliasFixer.php',
  2975. 'PhpCsFixer\\Fixer\\Import\\NoUnusedImportsFixer' => $baseDir . '/src/Fixer/Import/NoUnusedImportsFixer.php',
  2976. 'PhpCsFixer\\Fixer\\Import\\OrderedImportsFixer' => $baseDir . '/src/Fixer/Import/OrderedImportsFixer.php',
  2977. 'PhpCsFixer\\Fixer\\Import\\SingleImportPerStatementFixer' => $baseDir . '/src/Fixer/Import/SingleImportPerStatementFixer.php',
  2978. 'PhpCsFixer\\Fixer\\Import\\SingleLineAfterImportsFixer' => $baseDir . '/src/Fixer/Import/SingleLineAfterImportsFixer.php',
  2979. 'PhpCsFixer\\Fixer\\Indentation' => $baseDir . '/src/Fixer/Indentation.php',
  2980. 'PhpCsFixer\\Fixer\\InternalFixerInterface' => $baseDir . '/src/Fixer/InternalFixerInterface.php',
  2981. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ClassKeywordFixer' => $baseDir . '/src/Fixer/LanguageConstruct/ClassKeywordFixer.php',
  2982. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ClassKeywordRemoveFixer' => $baseDir . '/src/Fixer/LanguageConstruct/ClassKeywordRemoveFixer.php',
  2983. 'PhpCsFixer\\Fixer\\LanguageConstruct\\CombineConsecutiveIssetsFixer' => $baseDir . '/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php',
  2984. 'PhpCsFixer\\Fixer\\LanguageConstruct\\CombineConsecutiveUnsetsFixer' => $baseDir . '/src/Fixer/LanguageConstruct/CombineConsecutiveUnsetsFixer.php',
  2985. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DeclareEqualNormalizeFixer' => $baseDir . '/src/Fixer/LanguageConstruct/DeclareEqualNormalizeFixer.php',
  2986. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DeclareParenthesesFixer' => $baseDir . '/src/Fixer/LanguageConstruct/DeclareParenthesesFixer.php',
  2987. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DirConstantFixer' => $baseDir . '/src/Fixer/LanguageConstruct/DirConstantFixer.php',
  2988. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ErrorSuppressionFixer' => $baseDir . '/src/Fixer/LanguageConstruct/ErrorSuppressionFixer.php',
  2989. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ExplicitIndirectVariableFixer' => $baseDir . '/src/Fixer/LanguageConstruct/ExplicitIndirectVariableFixer.php',
  2990. 'PhpCsFixer\\Fixer\\LanguageConstruct\\FunctionToConstantFixer' => $baseDir . '/src/Fixer/LanguageConstruct/FunctionToConstantFixer.php',
  2991. 'PhpCsFixer\\Fixer\\LanguageConstruct\\GetClassToClassKeywordFixer' => $baseDir . '/src/Fixer/LanguageConstruct/GetClassToClassKeywordFixer.php',
  2992. 'PhpCsFixer\\Fixer\\LanguageConstruct\\IsNullFixer' => $baseDir . '/src/Fixer/LanguageConstruct/IsNullFixer.php',
  2993. 'PhpCsFixer\\Fixer\\LanguageConstruct\\NoUnsetOnPropertyFixer' => $baseDir . '/src/Fixer/LanguageConstruct/NoUnsetOnPropertyFixer.php',
  2994. 'PhpCsFixer\\Fixer\\LanguageConstruct\\NullableTypeDeclarationFixer' => $baseDir . '/src/Fixer/LanguageConstruct/NullableTypeDeclarationFixer.php',
  2995. 'PhpCsFixer\\Fixer\\LanguageConstruct\\SingleSpaceAfterConstructFixer' => $baseDir . '/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php',
  2996. 'PhpCsFixer\\Fixer\\LanguageConstruct\\SingleSpaceAroundConstructFixer' => $baseDir . '/src/Fixer/LanguageConstruct/SingleSpaceAroundConstructFixer.php',
  2997. 'PhpCsFixer\\Fixer\\ListNotation\\ListSyntaxFixer' => $baseDir . '/src/Fixer/ListNotation/ListSyntaxFixer.php',
  2998. 'PhpCsFixer\\Fixer\\NamespaceNotation\\BlankLineAfterNamespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixer.php',
  2999. 'PhpCsFixer\\Fixer\\NamespaceNotation\\BlankLinesBeforeNamespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/BlankLinesBeforeNamespaceFixer.php',
  3000. 'PhpCsFixer\\Fixer\\NamespaceNotation\\CleanNamespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/CleanNamespaceFixer.php',
  3001. 'PhpCsFixer\\Fixer\\NamespaceNotation\\NoBlankLinesBeforeNamespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/NoBlankLinesBeforeNamespaceFixer.php',
  3002. 'PhpCsFixer\\Fixer\\NamespaceNotation\\NoLeadingNamespaceWhitespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/NoLeadingNamespaceWhitespaceFixer.php',
  3003. 'PhpCsFixer\\Fixer\\NamespaceNotation\\SingleBlankLineBeforeNamespaceFixer' => $baseDir . '/src/Fixer/NamespaceNotation/SingleBlankLineBeforeNamespaceFixer.php',
  3004. 'PhpCsFixer\\Fixer\\Naming\\NoHomoglyphNamesFixer' => $baseDir . '/src/Fixer/Naming/NoHomoglyphNamesFixer.php',
  3005. 'PhpCsFixer\\Fixer\\Operator\\AssignNullCoalescingToCoalesceEqualFixer' => $baseDir . '/src/Fixer/Operator/AssignNullCoalescingToCoalesceEqualFixer.php',
  3006. 'PhpCsFixer\\Fixer\\Operator\\BinaryOperatorSpacesFixer' => $baseDir . '/src/Fixer/Operator/BinaryOperatorSpacesFixer.php',
  3007. 'PhpCsFixer\\Fixer\\Operator\\ConcatSpaceFixer' => $baseDir . '/src/Fixer/Operator/ConcatSpaceFixer.php',
  3008. 'PhpCsFixer\\Fixer\\Operator\\IncrementStyleFixer' => $baseDir . '/src/Fixer/Operator/IncrementStyleFixer.php',
  3009. 'PhpCsFixer\\Fixer\\Operator\\LogicalOperatorsFixer' => $baseDir . '/src/Fixer/Operator/LogicalOperatorsFixer.php',
  3010. 'PhpCsFixer\\Fixer\\Operator\\LongToShorthandOperatorFixer' => $baseDir . '/src/Fixer/Operator/LongToShorthandOperatorFixer.php',
  3011. 'PhpCsFixer\\Fixer\\Operator\\NewExpressionParenthesesFixer' => $baseDir . '/src/Fixer/Operator/NewExpressionParenthesesFixer.php',
  3012. 'PhpCsFixer\\Fixer\\Operator\\NewWithBracesFixer' => $baseDir . '/src/Fixer/Operator/NewWithBracesFixer.php',
  3013. 'PhpCsFixer\\Fixer\\Operator\\NewWithParenthesesFixer' => $baseDir . '/src/Fixer/Operator/NewWithParenthesesFixer.php',
  3014. 'PhpCsFixer\\Fixer\\Operator\\NoSpaceAroundDoubleColonFixer' => $baseDir . '/src/Fixer/Operator/NoSpaceAroundDoubleColonFixer.php',
  3015. 'PhpCsFixer\\Fixer\\Operator\\NoUselessConcatOperatorFixer' => $baseDir . '/src/Fixer/Operator/NoUselessConcatOperatorFixer.php',
  3016. 'PhpCsFixer\\Fixer\\Operator\\NoUselessNullsafeOperatorFixer' => $baseDir . '/src/Fixer/Operator/NoUselessNullsafeOperatorFixer.php',
  3017. 'PhpCsFixer\\Fixer\\Operator\\NotOperatorWithSpaceFixer' => $baseDir . '/src/Fixer/Operator/NotOperatorWithSpaceFixer.php',
  3018. 'PhpCsFixer\\Fixer\\Operator\\NotOperatorWithSuccessorSpaceFixer' => $baseDir . '/src/Fixer/Operator/NotOperatorWithSuccessorSpaceFixer.php',
  3019. 'PhpCsFixer\\Fixer\\Operator\\ObjectOperatorWithoutWhitespaceFixer' => $baseDir . '/src/Fixer/Operator/ObjectOperatorWithoutWhitespaceFixer.php',
  3020. 'PhpCsFixer\\Fixer\\Operator\\OperatorLinebreakFixer' => $baseDir . '/src/Fixer/Operator/OperatorLinebreakFixer.php',
  3021. 'PhpCsFixer\\Fixer\\Operator\\StandardizeIncrementFixer' => $baseDir . '/src/Fixer/Operator/StandardizeIncrementFixer.php',
  3022. 'PhpCsFixer\\Fixer\\Operator\\StandardizeNotEqualsFixer' => $baseDir . '/src/Fixer/Operator/StandardizeNotEqualsFixer.php',
  3023. 'PhpCsFixer\\Fixer\\Operator\\TernaryOperatorSpacesFixer' => $baseDir . '/src/Fixer/Operator/TernaryOperatorSpacesFixer.php',
  3024. 'PhpCsFixer\\Fixer\\Operator\\TernaryToElvisOperatorFixer' => $baseDir . '/src/Fixer/Operator/TernaryToElvisOperatorFixer.php',
  3025. 'PhpCsFixer\\Fixer\\Operator\\TernaryToNullCoalescingFixer' => $baseDir . '/src/Fixer/Operator/TernaryToNullCoalescingFixer.php',
  3026. 'PhpCsFixer\\Fixer\\Operator\\UnaryOperatorSpacesFixer' => $baseDir . '/src/Fixer/Operator/UnaryOperatorSpacesFixer.php',
  3027. 'PhpCsFixer\\Fixer\\PhpTag\\BlankLineAfterOpeningTagFixer' => $baseDir . '/src/Fixer/PhpTag/BlankLineAfterOpeningTagFixer.php',
  3028. 'PhpCsFixer\\Fixer\\PhpTag\\EchoTagSyntaxFixer' => $baseDir . '/src/Fixer/PhpTag/EchoTagSyntaxFixer.php',
  3029. 'PhpCsFixer\\Fixer\\PhpTag\\FullOpeningTagFixer' => $baseDir . '/src/Fixer/PhpTag/FullOpeningTagFixer.php',
  3030. 'PhpCsFixer\\Fixer\\PhpTag\\LinebreakAfterOpeningTagFixer' => $baseDir . '/src/Fixer/PhpTag/LinebreakAfterOpeningTagFixer.php',
  3031. 'PhpCsFixer\\Fixer\\PhpTag\\NoClosingTagFixer' => $baseDir . '/src/Fixer/PhpTag/NoClosingTagFixer.php',
  3032. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitAssertNewNamesFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitAssertNewNamesFixer.php',
  3033. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitAttributesFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitAttributesFixer.php',
  3034. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitConstructFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitConstructFixer.php',
  3035. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderMethodOrderFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDataProviderMethodOrderFixer.php',
  3036. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderNameFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDataProviderNameFixer.php',
  3037. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderReturnTypeFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDataProviderReturnTypeFixer.php',
  3038. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderStaticFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDataProviderStaticFixer.php',
  3039. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDedicateAssertFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php',
  3040. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDedicateAssertInternalTypeFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixer.php',
  3041. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitExpectationFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitExpectationFixer.php',
  3042. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitFqcnAnnotationFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixer.php',
  3043. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitInternalClassFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitInternalClassFixer.php',
  3044. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMethodCasingFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitMethodCasingFixer.php',
  3045. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMockFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitMockFixer.php',
  3046. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMockShortWillReturnFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitMockShortWillReturnFixer.php',
  3047. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitNamespacedFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php',
  3048. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitNoExpectationAnnotationFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitNoExpectationAnnotationFixer.php',
  3049. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitSetUpTearDownVisibilityFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitSetUpTearDownVisibilityFixer.php',
  3050. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitSizeClassFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitSizeClassFixer.php',
  3051. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitStrictFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitStrictFixer.php',
  3052. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTargetVersion' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitTargetVersion.php',
  3053. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestAnnotationFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php',
  3054. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestCaseStaticMethodCallsFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php',
  3055. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestClassRequiresCoversFixer' => $baseDir . '/src/Fixer/PhpUnit/PhpUnitTestClassRequiresCoversFixer.php',
  3056. 'PhpCsFixer\\Fixer\\Phpdoc\\AlignMultilineCommentFixer' => $baseDir . '/src/Fixer/Phpdoc/AlignMultilineCommentFixer.php',
  3057. 'PhpCsFixer\\Fixer\\Phpdoc\\GeneralPhpdocAnnotationRemoveFixer' => $baseDir . '/src/Fixer/Phpdoc/GeneralPhpdocAnnotationRemoveFixer.php',
  3058. 'PhpCsFixer\\Fixer\\Phpdoc\\GeneralPhpdocTagRenameFixer' => $baseDir . '/src/Fixer/Phpdoc/GeneralPhpdocTagRenameFixer.php',
  3059. 'PhpCsFixer\\Fixer\\Phpdoc\\NoBlankLinesAfterPhpdocFixer' => $baseDir . '/src/Fixer/Phpdoc/NoBlankLinesAfterPhpdocFixer.php',
  3060. 'PhpCsFixer\\Fixer\\Phpdoc\\NoEmptyPhpdocFixer' => $baseDir . '/src/Fixer/Phpdoc/NoEmptyPhpdocFixer.php',
  3061. 'PhpCsFixer\\Fixer\\Phpdoc\\NoSuperfluousPhpdocTagsFixer' => $baseDir . '/src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php',
  3062. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAddMissingParamAnnotationFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocAddMissingParamAnnotationFixer.php',
  3063. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAlignFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocAlignFixer.php',
  3064. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAnnotationWithoutDotFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocAnnotationWithoutDotFixer.php',
  3065. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocArrayTypeFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocArrayTypeFixer.php',
  3066. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocIndentFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocIndentFixer.php',
  3067. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocInlineTagNormalizerFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocInlineTagNormalizerFixer.php',
  3068. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocLineSpanFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocLineSpanFixer.php',
  3069. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocListTypeFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocListTypeFixer.php',
  3070. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoAccessFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocNoAccessFixer.php',
  3071. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoAliasTagFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocNoAliasTagFixer.php',
  3072. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoEmptyReturnFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocNoEmptyReturnFixer.php',
  3073. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoPackageFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocNoPackageFixer.php',
  3074. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoUselessInheritdocFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php',
  3075. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocOrderByValueFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocOrderByValueFixer.php',
  3076. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocOrderFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocOrderFixer.php',
  3077. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocParamOrderFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php',
  3078. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocReturnSelfReferenceFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php',
  3079. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocScalarFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocScalarFixer.php',
  3080. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSeparationFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocSeparationFixer.php',
  3081. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSingleLineVarSpacingFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocSingleLineVarSpacingFixer.php',
  3082. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSummaryFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocSummaryFixer.php',
  3083. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTagCasingFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTagCasingFixer.php',
  3084. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTagTypeFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php',
  3085. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocToCommentFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocToCommentFixer.php',
  3086. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTrimConsecutiveBlankLineSeparationFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTrimConsecutiveBlankLineSeparationFixer.php',
  3087. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTrimFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTrimFixer.php',
  3088. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTypesFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTypesFixer.php',
  3089. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTypesOrderFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php',
  3090. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocVarAnnotationCorrectOrderFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocVarAnnotationCorrectOrderFixer.php',
  3091. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocVarWithoutNameFixer' => $baseDir . '/src/Fixer/Phpdoc/PhpdocVarWithoutNameFixer.php',
  3092. 'PhpCsFixer\\Fixer\\ReturnNotation\\NoUselessReturnFixer' => $baseDir . '/src/Fixer/ReturnNotation/NoUselessReturnFixer.php',
  3093. 'PhpCsFixer\\Fixer\\ReturnNotation\\ReturnAssignmentFixer' => $baseDir . '/src/Fixer/ReturnNotation/ReturnAssignmentFixer.php',
  3094. 'PhpCsFixer\\Fixer\\ReturnNotation\\SimplifiedNullReturnFixer' => $baseDir . '/src/Fixer/ReturnNotation/SimplifiedNullReturnFixer.php',
  3095. 'PhpCsFixer\\Fixer\\Semicolon\\MultilineWhitespaceBeforeSemicolonsFixer' => $baseDir . '/src/Fixer/Semicolon/MultilineWhitespaceBeforeSemicolonsFixer.php',
  3096. 'PhpCsFixer\\Fixer\\Semicolon\\NoEmptyStatementFixer' => $baseDir . '/src/Fixer/Semicolon/NoEmptyStatementFixer.php',
  3097. 'PhpCsFixer\\Fixer\\Semicolon\\NoSinglelineWhitespaceBeforeSemicolonsFixer' => $baseDir . '/src/Fixer/Semicolon/NoSinglelineWhitespaceBeforeSemicolonsFixer.php',
  3098. 'PhpCsFixer\\Fixer\\Semicolon\\SemicolonAfterInstructionFixer' => $baseDir . '/src/Fixer/Semicolon/SemicolonAfterInstructionFixer.php',
  3099. 'PhpCsFixer\\Fixer\\Semicolon\\SpaceAfterSemicolonFixer' => $baseDir . '/src/Fixer/Semicolon/SpaceAfterSemicolonFixer.php',
  3100. 'PhpCsFixer\\Fixer\\Strict\\DeclareStrictTypesFixer' => $baseDir . '/src/Fixer/Strict/DeclareStrictTypesFixer.php',
  3101. 'PhpCsFixer\\Fixer\\Strict\\StrictComparisonFixer' => $baseDir . '/src/Fixer/Strict/StrictComparisonFixer.php',
  3102. 'PhpCsFixer\\Fixer\\Strict\\StrictParamFixer' => $baseDir . '/src/Fixer/Strict/StrictParamFixer.php',
  3103. 'PhpCsFixer\\Fixer\\StringNotation\\EscapeImplicitBackslashesFixer' => $baseDir . '/src/Fixer/StringNotation/EscapeImplicitBackslashesFixer.php',
  3104. 'PhpCsFixer\\Fixer\\StringNotation\\ExplicitStringVariableFixer' => $baseDir . '/src/Fixer/StringNotation/ExplicitStringVariableFixer.php',
  3105. 'PhpCsFixer\\Fixer\\StringNotation\\HeredocClosingMarkerFixer' => $baseDir . '/src/Fixer/StringNotation/HeredocClosingMarkerFixer.php',
  3106. 'PhpCsFixer\\Fixer\\StringNotation\\HeredocToNowdocFixer' => $baseDir . '/src/Fixer/StringNotation/HeredocToNowdocFixer.php',
  3107. 'PhpCsFixer\\Fixer\\StringNotation\\MultilineStringToHeredocFixer' => $baseDir . '/src/Fixer/StringNotation/MultilineStringToHeredocFixer.php',
  3108. 'PhpCsFixer\\Fixer\\StringNotation\\NoBinaryStringFixer' => $baseDir . '/src/Fixer/StringNotation/NoBinaryStringFixer.php',
  3109. 'PhpCsFixer\\Fixer\\StringNotation\\NoTrailingWhitespaceInStringFixer' => $baseDir . '/src/Fixer/StringNotation/NoTrailingWhitespaceInStringFixer.php',
  3110. 'PhpCsFixer\\Fixer\\StringNotation\\SimpleToComplexStringVariableFixer' => $baseDir . '/src/Fixer/StringNotation/SimpleToComplexStringVariableFixer.php',
  3111. 'PhpCsFixer\\Fixer\\StringNotation\\SingleQuoteFixer' => $baseDir . '/src/Fixer/StringNotation/SingleQuoteFixer.php',
  3112. 'PhpCsFixer\\Fixer\\StringNotation\\StringImplicitBackslashesFixer' => $baseDir . '/src/Fixer/StringNotation/StringImplicitBackslashesFixer.php',
  3113. 'PhpCsFixer\\Fixer\\StringNotation\\StringLengthToEmptyFixer' => $baseDir . '/src/Fixer/StringNotation/StringLengthToEmptyFixer.php',
  3114. 'PhpCsFixer\\Fixer\\StringNotation\\StringLineEndingFixer' => $baseDir . '/src/Fixer/StringNotation/StringLineEndingFixer.php',
  3115. 'PhpCsFixer\\Fixer\\Whitespace\\ArrayIndentationFixer' => $baseDir . '/src/Fixer/Whitespace/ArrayIndentationFixer.php',
  3116. 'PhpCsFixer\\Fixer\\Whitespace\\BlankLineBeforeStatementFixer' => $baseDir . '/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php',
  3117. 'PhpCsFixer\\Fixer\\Whitespace\\BlankLineBetweenImportGroupsFixer' => $baseDir . '/src/Fixer/Whitespace/BlankLineBetweenImportGroupsFixer.php',
  3118. 'PhpCsFixer\\Fixer\\Whitespace\\CompactNullableTypeDeclarationFixer' => $baseDir . '/src/Fixer/Whitespace/CompactNullableTypeDeclarationFixer.php',
  3119. 'PhpCsFixer\\Fixer\\Whitespace\\CompactNullableTypehintFixer' => $baseDir . '/src/Fixer/Whitespace/CompactNullableTypehintFixer.php',
  3120. 'PhpCsFixer\\Fixer\\Whitespace\\HeredocIndentationFixer' => $baseDir . '/src/Fixer/Whitespace/HeredocIndentationFixer.php',
  3121. 'PhpCsFixer\\Fixer\\Whitespace\\IndentationTypeFixer' => $baseDir . '/src/Fixer/Whitespace/IndentationTypeFixer.php',
  3122. 'PhpCsFixer\\Fixer\\Whitespace\\LineEndingFixer' => $baseDir . '/src/Fixer/Whitespace/LineEndingFixer.php',
  3123. 'PhpCsFixer\\Fixer\\Whitespace\\MethodChainingIndentationFixer' => $baseDir . '/src/Fixer/Whitespace/MethodChainingIndentationFixer.php',
  3124. 'PhpCsFixer\\Fixer\\Whitespace\\NoExtraBlankLinesFixer' => $baseDir . '/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php',
  3125. 'PhpCsFixer\\Fixer\\Whitespace\\NoSpacesAroundOffsetFixer' => $baseDir . '/src/Fixer/Whitespace/NoSpacesAroundOffsetFixer.php',
  3126. 'PhpCsFixer\\Fixer\\Whitespace\\NoSpacesInsideParenthesisFixer' => $baseDir . '/src/Fixer/Whitespace/NoSpacesInsideParenthesisFixer.php',
  3127. 'PhpCsFixer\\Fixer\\Whitespace\\NoTrailingWhitespaceFixer' => $baseDir . '/src/Fixer/Whitespace/NoTrailingWhitespaceFixer.php',
  3128. 'PhpCsFixer\\Fixer\\Whitespace\\NoWhitespaceInBlankLineFixer' => $baseDir . '/src/Fixer/Whitespace/NoWhitespaceInBlankLineFixer.php',
  3129. 'PhpCsFixer\\Fixer\\Whitespace\\SingleBlankLineAtEofFixer' => $baseDir . '/src/Fixer/Whitespace/SingleBlankLineAtEofFixer.php',
  3130. 'PhpCsFixer\\Fixer\\Whitespace\\SpacesInsideParenthesesFixer' => $baseDir . '/src/Fixer/Whitespace/SpacesInsideParenthesesFixer.php',
  3131. 'PhpCsFixer\\Fixer\\Whitespace\\StatementIndentationFixer' => $baseDir . '/src/Fixer/Whitespace/StatementIndentationFixer.php',
  3132. 'PhpCsFixer\\Fixer\\Whitespace\\TypeDeclarationSpacesFixer' => $baseDir . '/src/Fixer/Whitespace/TypeDeclarationSpacesFixer.php',
  3133. 'PhpCsFixer\\Fixer\\Whitespace\\TypesSpacesFixer' => $baseDir . '/src/Fixer/Whitespace/TypesSpacesFixer.php',
  3134. 'PhpCsFixer\\Fixer\\WhitespacesAwareFixerInterface' => $baseDir . '/src/Fixer/WhitespacesAwareFixerInterface.php',
  3135. 'PhpCsFixer\\Hasher' => $baseDir . '/src/Hasher.php',
  3136. 'PhpCsFixer\\Linter\\CachingLinter' => $baseDir . '/src/Linter/CachingLinter.php',
  3137. 'PhpCsFixer\\Linter\\Linter' => $baseDir . '/src/Linter/Linter.php',
  3138. 'PhpCsFixer\\Linter\\LinterInterface' => $baseDir . '/src/Linter/LinterInterface.php',
  3139. 'PhpCsFixer\\Linter\\LintingException' => $baseDir . '/src/Linter/LintingException.php',
  3140. 'PhpCsFixer\\Linter\\LintingResultInterface' => $baseDir . '/src/Linter/LintingResultInterface.php',
  3141. 'PhpCsFixer\\Linter\\ProcessLinter' => $baseDir . '/src/Linter/ProcessLinter.php',
  3142. 'PhpCsFixer\\Linter\\ProcessLinterProcessBuilder' => $baseDir . '/src/Linter/ProcessLinterProcessBuilder.php',
  3143. 'PhpCsFixer\\Linter\\ProcessLintingResult' => $baseDir . '/src/Linter/ProcessLintingResult.php',
  3144. 'PhpCsFixer\\Linter\\TokenizerLinter' => $baseDir . '/src/Linter/TokenizerLinter.php',
  3145. 'PhpCsFixer\\Linter\\TokenizerLintingResult' => $baseDir . '/src/Linter/TokenizerLintingResult.php',
  3146. 'PhpCsFixer\\Linter\\UnavailableLinterException' => $baseDir . '/src/Linter/UnavailableLinterException.php',
  3147. 'PhpCsFixer\\ParallelAwareConfigInterface' => $baseDir . '/src/ParallelAwareConfigInterface.php',
  3148. 'PhpCsFixer\\PharChecker' => $baseDir . '/src/PharChecker.php',
  3149. 'PhpCsFixer\\PharCheckerInterface' => $baseDir . '/src/PharCheckerInterface.php',
  3150. 'PhpCsFixer\\Preg' => $baseDir . '/src/Preg.php',
  3151. 'PhpCsFixer\\PregException' => $baseDir . '/src/PregException.php',
  3152. 'PhpCsFixer\\RuleSet\\AbstractMigrationSetDescription' => $baseDir . '/src/RuleSet/AbstractMigrationSetDescription.php',
  3153. 'PhpCsFixer\\RuleSet\\AbstractRuleSetDescription' => $baseDir . '/src/RuleSet/AbstractRuleSetDescription.php',
  3154. 'PhpCsFixer\\RuleSet\\DeprecatedRuleSetDescriptionInterface' => $baseDir . '/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php',
  3155. 'PhpCsFixer\\RuleSet\\RuleSet' => $baseDir . '/src/RuleSet/RuleSet.php',
  3156. 'PhpCsFixer\\RuleSet\\RuleSetDescriptionInterface' => $baseDir . '/src/RuleSet/RuleSetDescriptionInterface.php',
  3157. 'PhpCsFixer\\RuleSet\\RuleSetInterface' => $baseDir . '/src/RuleSet/RuleSetInterface.php',
  3158. 'PhpCsFixer\\RuleSet\\RuleSets' => $baseDir . '/src/RuleSet/RuleSets.php',
  3159. 'PhpCsFixer\\RuleSet\\Sets\\DoctrineAnnotationSet' => $baseDir . '/src/RuleSet/Sets/DoctrineAnnotationSet.php',
  3160. 'PhpCsFixer\\RuleSet\\Sets\\PERCS1x0RiskySet' => $baseDir . '/src/RuleSet/Sets/PERCS1x0RiskySet.php',
  3161. 'PhpCsFixer\\RuleSet\\Sets\\PERCS1x0Set' => $baseDir . '/src/RuleSet/Sets/PERCS1x0Set.php',
  3162. 'PhpCsFixer\\RuleSet\\Sets\\PERCS2x0RiskySet' => $baseDir . '/src/RuleSet/Sets/PERCS2x0RiskySet.php',
  3163. 'PhpCsFixer\\RuleSet\\Sets\\PERCS2x0Set' => $baseDir . '/src/RuleSet/Sets/PERCS2x0Set.php',
  3164. 'PhpCsFixer\\RuleSet\\Sets\\PERCSRiskySet' => $baseDir . '/src/RuleSet/Sets/PERCSRiskySet.php',
  3165. 'PhpCsFixer\\RuleSet\\Sets\\PERCSSet' => $baseDir . '/src/RuleSet/Sets/PERCSSet.php',
  3166. 'PhpCsFixer\\RuleSet\\Sets\\PERRiskySet' => $baseDir . '/src/RuleSet/Sets/PERRiskySet.php',
  3167. 'PhpCsFixer\\RuleSet\\Sets\\PERSet' => $baseDir . '/src/RuleSet/Sets/PERSet.php',
  3168. 'PhpCsFixer\\RuleSet\\Sets\\PHP54MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP54MigrationSet.php',
  3169. 'PhpCsFixer\\RuleSet\\Sets\\PHP56MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP56MigrationRiskySet.php',
  3170. 'PhpCsFixer\\RuleSet\\Sets\\PHP70MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP70MigrationRiskySet.php',
  3171. 'PhpCsFixer\\RuleSet\\Sets\\PHP70MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP70MigrationSet.php',
  3172. 'PhpCsFixer\\RuleSet\\Sets\\PHP71MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP71MigrationRiskySet.php',
  3173. 'PhpCsFixer\\RuleSet\\Sets\\PHP71MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP71MigrationSet.php',
  3174. 'PhpCsFixer\\RuleSet\\Sets\\PHP73MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP73MigrationSet.php',
  3175. 'PhpCsFixer\\RuleSet\\Sets\\PHP74MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP74MigrationRiskySet.php',
  3176. 'PhpCsFixer\\RuleSet\\Sets\\PHP74MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP74MigrationSet.php',
  3177. 'PhpCsFixer\\RuleSet\\Sets\\PHP80MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP80MigrationRiskySet.php',
  3178. 'PhpCsFixer\\RuleSet\\Sets\\PHP80MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP80MigrationSet.php',
  3179. 'PhpCsFixer\\RuleSet\\Sets\\PHP81MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP81MigrationSet.php',
  3180. 'PhpCsFixer\\RuleSet\\Sets\\PHP82MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHP82MigrationRiskySet.php',
  3181. 'PhpCsFixer\\RuleSet\\Sets\\PHP82MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP82MigrationSet.php',
  3182. 'PhpCsFixer\\RuleSet\\Sets\\PHP83MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP83MigrationSet.php',
  3183. 'PhpCsFixer\\RuleSet\\Sets\\PHP84MigrationSet' => $baseDir . '/src/RuleSet/Sets/PHP84MigrationSet.php',
  3184. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit100MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit100MigrationRiskySet.php',
  3185. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit30MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit30MigrationRiskySet.php',
  3186. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit32MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit32MigrationRiskySet.php',
  3187. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit35MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit35MigrationRiskySet.php',
  3188. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit43MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit43MigrationRiskySet.php',
  3189. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit48MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit48MigrationRiskySet.php',
  3190. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit50MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit50MigrationRiskySet.php',
  3191. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit52MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit52MigrationRiskySet.php',
  3192. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit54MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit54MigrationRiskySet.php',
  3193. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit55MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit55MigrationRiskySet.php',
  3194. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit56MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit56MigrationRiskySet.php',
  3195. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit57MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit57MigrationRiskySet.php',
  3196. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit60MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit60MigrationRiskySet.php',
  3197. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit75MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit75MigrationRiskySet.php',
  3198. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit84MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit84MigrationRiskySet.php',
  3199. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit91MigrationRiskySet' => $baseDir . '/src/RuleSet/Sets/PHPUnit91MigrationRiskySet.php',
  3200. 'PhpCsFixer\\RuleSet\\Sets\\PSR12RiskySet' => $baseDir . '/src/RuleSet/Sets/PSR12RiskySet.php',
  3201. 'PhpCsFixer\\RuleSet\\Sets\\PSR12Set' => $baseDir . '/src/RuleSet/Sets/PSR12Set.php',
  3202. 'PhpCsFixer\\RuleSet\\Sets\\PSR1Set' => $baseDir . '/src/RuleSet/Sets/PSR1Set.php',
  3203. 'PhpCsFixer\\RuleSet\\Sets\\PSR2Set' => $baseDir . '/src/RuleSet/Sets/PSR2Set.php',
  3204. 'PhpCsFixer\\RuleSet\\Sets\\PhpCsFixerRiskySet' => $baseDir . '/src/RuleSet/Sets/PhpCsFixerRiskySet.php',
  3205. 'PhpCsFixer\\RuleSet\\Sets\\PhpCsFixerSet' => $baseDir . '/src/RuleSet/Sets/PhpCsFixerSet.php',
  3206. 'PhpCsFixer\\RuleSet\\Sets\\SymfonyRiskySet' => $baseDir . '/src/RuleSet/Sets/SymfonyRiskySet.php',
  3207. 'PhpCsFixer\\RuleSet\\Sets\\SymfonySet' => $baseDir . '/src/RuleSet/Sets/SymfonySet.php',
  3208. 'PhpCsFixer\\Runner\\Event\\AnalysisStarted' => $baseDir . '/src/Runner/Event/AnalysisStarted.php',
  3209. 'PhpCsFixer\\Runner\\Event\\FileProcessed' => $baseDir . '/src/Runner/Event/FileProcessed.php',
  3210. 'PhpCsFixer\\Runner\\FileCachingLintingFileIterator' => $baseDir . '/src/Runner/FileCachingLintingFileIterator.php',
  3211. 'PhpCsFixer\\Runner\\FileFilterIterator' => $baseDir . '/src/Runner/FileFilterIterator.php',
  3212. 'PhpCsFixer\\Runner\\LintingFileIterator' => $baseDir . '/src/Runner/LintingFileIterator.php',
  3213. 'PhpCsFixer\\Runner\\LintingResultAwareFileIteratorInterface' => $baseDir . '/src/Runner/LintingResultAwareFileIteratorInterface.php',
  3214. 'PhpCsFixer\\Runner\\Parallel\\ParallelAction' => $baseDir . '/src/Runner/Parallel/ParallelAction.php',
  3215. 'PhpCsFixer\\Runner\\Parallel\\ParallelConfig' => $baseDir . '/src/Runner/Parallel/ParallelConfig.php',
  3216. 'PhpCsFixer\\Runner\\Parallel\\ParallelConfigFactory' => $baseDir . '/src/Runner/Parallel/ParallelConfigFactory.php',
  3217. 'PhpCsFixer\\Runner\\Parallel\\ParallelisationException' => $baseDir . '/src/Runner/Parallel/ParallelisationException.php',
  3218. 'PhpCsFixer\\Runner\\Parallel\\Process' => $baseDir . '/src/Runner/Parallel/Process.php',
  3219. 'PhpCsFixer\\Runner\\Parallel\\ProcessFactory' => $baseDir . '/src/Runner/Parallel/ProcessFactory.php',
  3220. 'PhpCsFixer\\Runner\\Parallel\\ProcessIdentifier' => $baseDir . '/src/Runner/Parallel/ProcessIdentifier.php',
  3221. 'PhpCsFixer\\Runner\\Parallel\\ProcessPool' => $baseDir . '/src/Runner/Parallel/ProcessPool.php',
  3222. 'PhpCsFixer\\Runner\\Parallel\\WorkerException' => $baseDir . '/src/Runner/Parallel/WorkerException.php',
  3223. 'PhpCsFixer\\Runner\\Runner' => $baseDir . '/src/Runner/Runner.php',
  3224. 'PhpCsFixer\\Runner\\RunnerConfig' => $baseDir . '/src/Runner/RunnerConfig.php',
  3225. 'PhpCsFixer\\StdinFileInfo' => $baseDir . '/src/StdinFileInfo.php',
  3226. 'PhpCsFixer\\Tokenizer\\AbstractTransformer' => $baseDir . '/src/Tokenizer/AbstractTransformer.php',
  3227. 'PhpCsFixer\\Tokenizer\\AbstractTypeTransformer' => $baseDir . '/src/Tokenizer/AbstractTypeTransformer.php',
  3228. 'PhpCsFixer\\Tokenizer\\Analyzer\\AlternativeSyntaxAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/AlternativeSyntaxAnalyzer.php',
  3229. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\AbstractControlCaseStructuresAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/AbstractControlCaseStructuresAnalysis.php',
  3230. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\ArgumentAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/ArgumentAnalysis.php',
  3231. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\AttributeAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/AttributeAnalysis.php',
  3232. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\CaseAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/CaseAnalysis.php',
  3233. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\DataProviderAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/DataProviderAnalysis.php',
  3234. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\DefaultAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/DefaultAnalysis.php',
  3235. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\EnumAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/EnumAnalysis.php',
  3236. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\MatchAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/MatchAnalysis.php',
  3237. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\NamespaceAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/NamespaceAnalysis.php',
  3238. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\NamespaceUseAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/NamespaceUseAnalysis.php',
  3239. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\StartEndTokenAwareAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/StartEndTokenAwareAnalysis.php',
  3240. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\SwitchAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/SwitchAnalysis.php',
  3241. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\TypeAnalysis' => $baseDir . '/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php',
  3242. 'PhpCsFixer\\Tokenizer\\Analyzer\\ArgumentsAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/ArgumentsAnalyzer.php',
  3243. 'PhpCsFixer\\Tokenizer\\Analyzer\\AttributeAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/AttributeAnalyzer.php',
  3244. 'PhpCsFixer\\Tokenizer\\Analyzer\\BlocksAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/BlocksAnalyzer.php',
  3245. 'PhpCsFixer\\Tokenizer\\Analyzer\\ClassyAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/ClassyAnalyzer.php',
  3246. 'PhpCsFixer\\Tokenizer\\Analyzer\\CommentsAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/CommentsAnalyzer.php',
  3247. 'PhpCsFixer\\Tokenizer\\Analyzer\\ControlCaseStructuresAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/ControlCaseStructuresAnalyzer.php',
  3248. 'PhpCsFixer\\Tokenizer\\Analyzer\\DataProviderAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/DataProviderAnalyzer.php',
  3249. 'PhpCsFixer\\Tokenizer\\Analyzer\\FullyQualifiedNameAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/FullyQualifiedNameAnalyzer.php',
  3250. 'PhpCsFixer\\Tokenizer\\Analyzer\\FunctionsAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/FunctionsAnalyzer.php',
  3251. 'PhpCsFixer\\Tokenizer\\Analyzer\\GotoLabelAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/GotoLabelAnalyzer.php',
  3252. 'PhpCsFixer\\Tokenizer\\Analyzer\\NamespaceUsesAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/NamespaceUsesAnalyzer.php',
  3253. 'PhpCsFixer\\Tokenizer\\Analyzer\\NamespacesAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/NamespacesAnalyzer.php',
  3254. 'PhpCsFixer\\Tokenizer\\Analyzer\\PhpUnitTestCaseAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/PhpUnitTestCaseAnalyzer.php',
  3255. 'PhpCsFixer\\Tokenizer\\Analyzer\\RangeAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/RangeAnalyzer.php',
  3256. 'PhpCsFixer\\Tokenizer\\Analyzer\\ReferenceAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/ReferenceAnalyzer.php',
  3257. 'PhpCsFixer\\Tokenizer\\Analyzer\\SwitchAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/SwitchAnalyzer.php',
  3258. 'PhpCsFixer\\Tokenizer\\Analyzer\\WhitespacesAnalyzer' => $baseDir . '/src/Tokenizer/Analyzer/WhitespacesAnalyzer.php',
  3259. 'PhpCsFixer\\Tokenizer\\CT' => $baseDir . '/src/Tokenizer/CT.php',
  3260. 'PhpCsFixer\\Tokenizer\\FCT' => $baseDir . '/src/Tokenizer/FCT.php',
  3261. 'PhpCsFixer\\Tokenizer\\Processor\\ImportProcessor' => $baseDir . '/src/Tokenizer/Processor/ImportProcessor.php',
  3262. 'PhpCsFixer\\Tokenizer\\Token' => $baseDir . '/src/Tokenizer/Token.php',
  3263. 'PhpCsFixer\\Tokenizer\\Tokens' => $baseDir . '/src/Tokenizer/Tokens.php',
  3264. 'PhpCsFixer\\Tokenizer\\TokensAnalyzer' => $baseDir . '/src/Tokenizer/TokensAnalyzer.php',
  3265. 'PhpCsFixer\\Tokenizer\\TransformerInterface' => $baseDir . '/src/Tokenizer/TransformerInterface.php',
  3266. 'PhpCsFixer\\Tokenizer\\Transformer\\ArrayTypehintTransformer' => $baseDir . '/src/Tokenizer/Transformer/ArrayTypehintTransformer.php',
  3267. 'PhpCsFixer\\Tokenizer\\Transformer\\AttributeTransformer' => $baseDir . '/src/Tokenizer/Transformer/AttributeTransformer.php',
  3268. 'PhpCsFixer\\Tokenizer\\Transformer\\BraceClassInstantiationTransformer' => $baseDir . '/src/Tokenizer/Transformer/BraceClassInstantiationTransformer.php',
  3269. 'PhpCsFixer\\Tokenizer\\Transformer\\BraceTransformer' => $baseDir . '/src/Tokenizer/Transformer/BraceTransformer.php',
  3270. 'PhpCsFixer\\Tokenizer\\Transformer\\ClassConstantTransformer' => $baseDir . '/src/Tokenizer/Transformer/ClassConstantTransformer.php',
  3271. 'PhpCsFixer\\Tokenizer\\Transformer\\ConstructorPromotionTransformer' => $baseDir . '/src/Tokenizer/Transformer/ConstructorPromotionTransformer.php',
  3272. 'PhpCsFixer\\Tokenizer\\Transformer\\DisjunctiveNormalFormTypeParenthesisTransformer' => $baseDir . '/src/Tokenizer/Transformer/DisjunctiveNormalFormTypeParenthesisTransformer.php',
  3273. 'PhpCsFixer\\Tokenizer\\Transformer\\FirstClassCallableTransformer' => $baseDir . '/src/Tokenizer/Transformer/FirstClassCallableTransformer.php',
  3274. 'PhpCsFixer\\Tokenizer\\Transformer\\ImportTransformer' => $baseDir . '/src/Tokenizer/Transformer/ImportTransformer.php',
  3275. 'PhpCsFixer\\Tokenizer\\Transformer\\NameQualifiedTransformer' => $baseDir . '/src/Tokenizer/Transformer/NameQualifiedTransformer.php',
  3276. 'PhpCsFixer\\Tokenizer\\Transformer\\NamedArgumentTransformer' => $baseDir . '/src/Tokenizer/Transformer/NamedArgumentTransformer.php',
  3277. 'PhpCsFixer\\Tokenizer\\Transformer\\NamespaceOperatorTransformer' => $baseDir . '/src/Tokenizer/Transformer/NamespaceOperatorTransformer.php',
  3278. 'PhpCsFixer\\Tokenizer\\Transformer\\NullableTypeTransformer' => $baseDir . '/src/Tokenizer/Transformer/NullableTypeTransformer.php',
  3279. 'PhpCsFixer\\Tokenizer\\Transformer\\ReturnRefTransformer' => $baseDir . '/src/Tokenizer/Transformer/ReturnRefTransformer.php',
  3280. 'PhpCsFixer\\Tokenizer\\Transformer\\SquareBraceTransformer' => $baseDir . '/src/Tokenizer/Transformer/SquareBraceTransformer.php',
  3281. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeAlternationTransformer' => $baseDir . '/src/Tokenizer/Transformer/TypeAlternationTransformer.php',
  3282. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeColonTransformer' => $baseDir . '/src/Tokenizer/Transformer/TypeColonTransformer.php',
  3283. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeIntersectionTransformer' => $baseDir . '/src/Tokenizer/Transformer/TypeIntersectionTransformer.php',
  3284. 'PhpCsFixer\\Tokenizer\\Transformer\\UseTransformer' => $baseDir . '/src/Tokenizer/Transformer/UseTransformer.php',
  3285. 'PhpCsFixer\\Tokenizer\\Transformer\\WhitespacyCommentTransformer' => $baseDir . '/src/Tokenizer/Transformer/WhitespacyCommentTransformer.php',
  3286. 'PhpCsFixer\\Tokenizer\\Transformers' => $baseDir . '/src/Tokenizer/Transformers.php',
  3287. 'PhpCsFixer\\ToolInfo' => $baseDir . '/src/ToolInfo.php',
  3288. 'PhpCsFixer\\ToolInfoInterface' => $baseDir . '/src/ToolInfoInterface.php',
  3289. 'PhpCsFixer\\UnsupportedPhpVersionAllowedConfigInterface' => $baseDir . '/src/UnsupportedPhpVersionAllowedConfigInterface.php',
  3290. 'PhpCsFixer\\Utils' => $baseDir . '/src/Utils.php',
  3291. 'PhpCsFixer\\WhitespacesFixerConfig' => $baseDir . '/src/WhitespacesFixerConfig.php',
  3292. 'PhpCsFixer\\WordMatcher' => $baseDir . '/src/WordMatcher.php',
  3293. 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
  3294. 'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
  3295. 'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
  3296. 'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
  3297. 'Psr\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/psr/event-dispatcher/src/EventDispatcherInterface.php',
  3298. 'Psr\\EventDispatcher\\ListenerProviderInterface' => $vendorDir . '/psr/event-dispatcher/src/ListenerProviderInterface.php',
  3299. 'Psr\\EventDispatcher\\StoppableEventInterface' => $vendorDir . '/psr/event-dispatcher/src/StoppableEventInterface.php',
  3300. 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php',
  3301. 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php',
  3302. 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php',
  3303. 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php',
  3304. 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php',
  3305. 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php',
  3306. 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php',
  3307. 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php',
  3308. 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php',
  3309. 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
  3310. 'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php',
  3311. 'React\\Cache\\ArrayCache' => $vendorDir . '/react/cache/src/ArrayCache.php',
  3312. 'React\\Cache\\CacheInterface' => $vendorDir . '/react/cache/src/CacheInterface.php',
  3313. 'React\\ChildProcess\\Process' => $vendorDir . '/react/child-process/src/Process.php',
  3314. 'React\\Dns\\BadServerException' => $vendorDir . '/react/dns/src/BadServerException.php',
  3315. 'React\\Dns\\Config\\Config' => $vendorDir . '/react/dns/src/Config/Config.php',
  3316. 'React\\Dns\\Config\\HostsFile' => $vendorDir . '/react/dns/src/Config/HostsFile.php',
  3317. 'React\\Dns\\Model\\Message' => $vendorDir . '/react/dns/src/Model/Message.php',
  3318. 'React\\Dns\\Model\\Record' => $vendorDir . '/react/dns/src/Model/Record.php',
  3319. 'React\\Dns\\Protocol\\BinaryDumper' => $vendorDir . '/react/dns/src/Protocol/BinaryDumper.php',
  3320. 'React\\Dns\\Protocol\\Parser' => $vendorDir . '/react/dns/src/Protocol/Parser.php',
  3321. 'React\\Dns\\Query\\CachingExecutor' => $vendorDir . '/react/dns/src/Query/CachingExecutor.php',
  3322. 'React\\Dns\\Query\\CancellationException' => $vendorDir . '/react/dns/src/Query/CancellationException.php',
  3323. 'React\\Dns\\Query\\CoopExecutor' => $vendorDir . '/react/dns/src/Query/CoopExecutor.php',
  3324. 'React\\Dns\\Query\\ExecutorInterface' => $vendorDir . '/react/dns/src/Query/ExecutorInterface.php',
  3325. 'React\\Dns\\Query\\FallbackExecutor' => $vendorDir . '/react/dns/src/Query/FallbackExecutor.php',
  3326. 'React\\Dns\\Query\\HostsFileExecutor' => $vendorDir . '/react/dns/src/Query/HostsFileExecutor.php',
  3327. 'React\\Dns\\Query\\Query' => $vendorDir . '/react/dns/src/Query/Query.php',
  3328. 'React\\Dns\\Query\\RetryExecutor' => $vendorDir . '/react/dns/src/Query/RetryExecutor.php',
  3329. 'React\\Dns\\Query\\SelectiveTransportExecutor' => $vendorDir . '/react/dns/src/Query/SelectiveTransportExecutor.php',
  3330. 'React\\Dns\\Query\\TcpTransportExecutor' => $vendorDir . '/react/dns/src/Query/TcpTransportExecutor.php',
  3331. 'React\\Dns\\Query\\TimeoutException' => $vendorDir . '/react/dns/src/Query/TimeoutException.php',
  3332. 'React\\Dns\\Query\\TimeoutExecutor' => $vendorDir . '/react/dns/src/Query/TimeoutExecutor.php',
  3333. 'React\\Dns\\Query\\UdpTransportExecutor' => $vendorDir . '/react/dns/src/Query/UdpTransportExecutor.php',
  3334. 'React\\Dns\\RecordNotFoundException' => $vendorDir . '/react/dns/src/RecordNotFoundException.php',
  3335. 'React\\Dns\\Resolver\\Factory' => $vendorDir . '/react/dns/src/Resolver/Factory.php',
  3336. 'React\\Dns\\Resolver\\Resolver' => $vendorDir . '/react/dns/src/Resolver/Resolver.php',
  3337. 'React\\Dns\\Resolver\\ResolverInterface' => $vendorDir . '/react/dns/src/Resolver/ResolverInterface.php',
  3338. 'React\\EventLoop\\ExtEvLoop' => $vendorDir . '/react/event-loop/src/ExtEvLoop.php',
  3339. 'React\\EventLoop\\ExtEventLoop' => $vendorDir . '/react/event-loop/src/ExtEventLoop.php',
  3340. 'React\\EventLoop\\ExtLibevLoop' => $vendorDir . '/react/event-loop/src/ExtLibevLoop.php',
  3341. 'React\\EventLoop\\ExtLibeventLoop' => $vendorDir . '/react/event-loop/src/ExtLibeventLoop.php',
  3342. 'React\\EventLoop\\ExtUvLoop' => $vendorDir . '/react/event-loop/src/ExtUvLoop.php',
  3343. 'React\\EventLoop\\Factory' => $vendorDir . '/react/event-loop/src/Factory.php',
  3344. 'React\\EventLoop\\Loop' => $vendorDir . '/react/event-loop/src/Loop.php',
  3345. 'React\\EventLoop\\LoopInterface' => $vendorDir . '/react/event-loop/src/LoopInterface.php',
  3346. 'React\\EventLoop\\SignalsHandler' => $vendorDir . '/react/event-loop/src/SignalsHandler.php',
  3347. 'React\\EventLoop\\StreamSelectLoop' => $vendorDir . '/react/event-loop/src/StreamSelectLoop.php',
  3348. 'React\\EventLoop\\Tick\\FutureTickQueue' => $vendorDir . '/react/event-loop/src/Tick/FutureTickQueue.php',
  3349. 'React\\EventLoop\\TimerInterface' => $vendorDir . '/react/event-loop/src/TimerInterface.php',
  3350. 'React\\EventLoop\\Timer\\Timer' => $vendorDir . '/react/event-loop/src/Timer/Timer.php',
  3351. 'React\\EventLoop\\Timer\\Timers' => $vendorDir . '/react/event-loop/src/Timer/Timers.php',
  3352. 'React\\Promise\\Deferred' => $vendorDir . '/react/promise/src/Deferred.php',
  3353. 'React\\Promise\\Exception\\CompositeException' => $vendorDir . '/react/promise/src/Exception/CompositeException.php',
  3354. 'React\\Promise\\Exception\\LengthException' => $vendorDir . '/react/promise/src/Exception/LengthException.php',
  3355. 'React\\Promise\\Internal\\CancellationQueue' => $vendorDir . '/react/promise/src/Internal/CancellationQueue.php',
  3356. 'React\\Promise\\Internal\\FulfilledPromise' => $vendorDir . '/react/promise/src/Internal/FulfilledPromise.php',
  3357. 'React\\Promise\\Internal\\RejectedPromise' => $vendorDir . '/react/promise/src/Internal/RejectedPromise.php',
  3358. 'React\\Promise\\Promise' => $vendorDir . '/react/promise/src/Promise.php',
  3359. 'React\\Promise\\PromiseInterface' => $vendorDir . '/react/promise/src/PromiseInterface.php',
  3360. 'React\\Socket\\Connection' => $vendorDir . '/react/socket/src/Connection.php',
  3361. 'React\\Socket\\ConnectionInterface' => $vendorDir . '/react/socket/src/ConnectionInterface.php',
  3362. 'React\\Socket\\Connector' => $vendorDir . '/react/socket/src/Connector.php',
  3363. 'React\\Socket\\ConnectorInterface' => $vendorDir . '/react/socket/src/ConnectorInterface.php',
  3364. 'React\\Socket\\DnsConnector' => $vendorDir . '/react/socket/src/DnsConnector.php',
  3365. 'React\\Socket\\FdServer' => $vendorDir . '/react/socket/src/FdServer.php',
  3366. 'React\\Socket\\FixedUriConnector' => $vendorDir . '/react/socket/src/FixedUriConnector.php',
  3367. 'React\\Socket\\HappyEyeBallsConnectionBuilder' => $vendorDir . '/react/socket/src/HappyEyeBallsConnectionBuilder.php',
  3368. 'React\\Socket\\HappyEyeBallsConnector' => $vendorDir . '/react/socket/src/HappyEyeBallsConnector.php',
  3369. 'React\\Socket\\LimitingServer' => $vendorDir . '/react/socket/src/LimitingServer.php',
  3370. 'React\\Socket\\SecureConnector' => $vendorDir . '/react/socket/src/SecureConnector.php',
  3371. 'React\\Socket\\SecureServer' => $vendorDir . '/react/socket/src/SecureServer.php',
  3372. 'React\\Socket\\Server' => $vendorDir . '/react/socket/src/Server.php',
  3373. 'React\\Socket\\ServerInterface' => $vendorDir . '/react/socket/src/ServerInterface.php',
  3374. 'React\\Socket\\SocketServer' => $vendorDir . '/react/socket/src/SocketServer.php',
  3375. 'React\\Socket\\StreamEncryption' => $vendorDir . '/react/socket/src/StreamEncryption.php',
  3376. 'React\\Socket\\TcpConnector' => $vendorDir . '/react/socket/src/TcpConnector.php',
  3377. 'React\\Socket\\TcpServer' => $vendorDir . '/react/socket/src/TcpServer.php',
  3378. 'React\\Socket\\TimeoutConnector' => $vendorDir . '/react/socket/src/TimeoutConnector.php',
  3379. 'React\\Socket\\UnixConnector' => $vendorDir . '/react/socket/src/UnixConnector.php',
  3380. 'React\\Socket\\UnixServer' => $vendorDir . '/react/socket/src/UnixServer.php',
  3381. 'React\\Stream\\CompositeStream' => $vendorDir . '/react/stream/src/CompositeStream.php',
  3382. 'React\\Stream\\DuplexResourceStream' => $vendorDir . '/react/stream/src/DuplexResourceStream.php',
  3383. 'React\\Stream\\DuplexStreamInterface' => $vendorDir . '/react/stream/src/DuplexStreamInterface.php',
  3384. 'React\\Stream\\ReadableResourceStream' => $vendorDir . '/react/stream/src/ReadableResourceStream.php',
  3385. 'React\\Stream\\ReadableStreamInterface' => $vendorDir . '/react/stream/src/ReadableStreamInterface.php',
  3386. 'React\\Stream\\ThroughStream' => $vendorDir . '/react/stream/src/ThroughStream.php',
  3387. 'React\\Stream\\Util' => $vendorDir . '/react/stream/src/Util.php',
  3388. 'React\\Stream\\WritableResourceStream' => $vendorDir . '/react/stream/src/WritableResourceStream.php',
  3389. 'React\\Stream\\WritableStreamInterface' => $vendorDir . '/react/stream/src/WritableStreamInterface.php',
  3390. 'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
  3391. 'SebastianBergmann\\Diff\\Chunk' => $vendorDir . '/sebastian/diff/src/Chunk.php',
  3392. 'SebastianBergmann\\Diff\\ConfigurationException' => $vendorDir . '/sebastian/diff/src/Exception/ConfigurationException.php',
  3393. 'SebastianBergmann\\Diff\\Diff' => $vendorDir . '/sebastian/diff/src/Diff.php',
  3394. 'SebastianBergmann\\Diff\\Differ' => $vendorDir . '/sebastian/diff/src/Differ.php',
  3395. 'SebastianBergmann\\Diff\\Exception' => $vendorDir . '/sebastian/diff/src/Exception/Exception.php',
  3396. 'SebastianBergmann\\Diff\\InvalidArgumentException' => $vendorDir . '/sebastian/diff/src/Exception/InvalidArgumentException.php',
  3397. 'SebastianBergmann\\Diff\\Line' => $vendorDir . '/sebastian/diff/src/Line.php',
  3398. 'SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php',
  3399. 'SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  3400. 'SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php',
  3401. 'SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php',
  3402. 'SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => $vendorDir . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php',
  3403. 'SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php',
  3404. 'SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php',
  3405. 'SebastianBergmann\\Diff\\Parser' => $vendorDir . '/sebastian/diff/src/Parser.php',
  3406. 'SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php',
  3407. 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
  3408. 'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php',
  3409. 'Symfony\\Component\\Console\\Attribute\\AsCommand' => $vendorDir . '/symfony/console/Attribute/AsCommand.php',
  3410. 'Symfony\\Component\\Console\\CI\\GithubActionReporter' => $vendorDir . '/symfony/console/CI/GithubActionReporter.php',
  3411. 'Symfony\\Component\\Console\\Color' => $vendorDir . '/symfony/console/Color.php',
  3412. 'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
  3413. 'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
  3414. 'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
  3415. 'Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php',
  3416. 'Symfony\\Component\\Console\\Command\\CompleteCommand' => $vendorDir . '/symfony/console/Command/CompleteCommand.php',
  3417. 'Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => $vendorDir . '/symfony/console/Command/DumpCompletionCommand.php',
  3418. 'Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php',
  3419. 'Symfony\\Component\\Console\\Command\\LazyCommand' => $vendorDir . '/symfony/console/Command/LazyCommand.php',
  3420. 'Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php',
  3421. 'Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php',
  3422. 'Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => $vendorDir . '/symfony/console/Command/SignalableCommandInterface.php',
  3423. 'Symfony\\Component\\Console\\Completion\\CompletionInput' => $vendorDir . '/symfony/console/Completion/CompletionInput.php',
  3424. 'Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => $vendorDir . '/symfony/console/Completion/CompletionSuggestions.php',
  3425. 'Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/BashCompletionOutput.php',
  3426. 'Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => $vendorDir . '/symfony/console/Completion/Output/CompletionOutputInterface.php',
  3427. 'Symfony\\Component\\Console\\Completion\\Suggestion' => $vendorDir . '/symfony/console/Completion/Suggestion.php',
  3428. 'Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php',
  3429. 'Symfony\\Component\\Console\\Cursor' => $vendorDir . '/symfony/console/Cursor.php',
  3430. 'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
  3431. 'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php',
  3432. 'Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php',
  3433. 'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php',
  3434. 'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php',
  3435. 'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php',
  3436. 'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php',
  3437. 'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php',
  3438. 'Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php',
  3439. 'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php',
  3440. 'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php',
  3441. 'Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php',
  3442. 'Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => $vendorDir . '/symfony/console/Event/ConsoleSignalEvent.php',
  3443. 'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php',
  3444. 'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php',
  3445. 'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php',
  3446. 'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php',
  3447. 'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php',
  3448. 'Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php',
  3449. 'Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php',
  3450. 'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php',
  3451. 'Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php',
  3452. 'Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatter.php',
  3453. 'Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatterStyle.php',
  3454. 'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php',
  3455. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php',
  3456. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php',
  3457. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
  3458. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
  3459. 'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
  3460. 'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php',
  3461. 'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php',
  3462. 'Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php',
  3463. 'Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php',
  3464. 'Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php',
  3465. 'Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php',
  3466. 'Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php',
  3467. 'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php',
  3468. 'Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php',
  3469. 'Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php',
  3470. 'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php',
  3471. 'Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php',
  3472. 'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php',
  3473. 'Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php',
  3474. 'Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php',
  3475. 'Symfony\\Component\\Console\\Helper\\TableCellStyle' => $vendorDir . '/symfony/console/Helper/TableCellStyle.php',
  3476. 'Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php',
  3477. 'Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php',
  3478. 'Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php',
  3479. 'Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php',
  3480. 'Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php',
  3481. 'Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php',
  3482. 'Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php',
  3483. 'Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php',
  3484. 'Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php',
  3485. 'Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php',
  3486. 'Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php',
  3487. 'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php',
  3488. 'Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php',
  3489. 'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php',
  3490. 'Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php',
  3491. 'Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php',
  3492. 'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php',
  3493. 'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php',
  3494. 'Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php',
  3495. 'Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php',
  3496. 'Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php',
  3497. 'Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php',
  3498. 'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php',
  3499. 'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php',
  3500. 'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php',
  3501. 'Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php',
  3502. 'Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => $vendorDir . '/symfony/console/SignalRegistry/SignalRegistry.php',
  3503. 'Symfony\\Component\\Console\\SingleCommandApplication' => $vendorDir . '/symfony/console/SingleCommandApplication.php',
  3504. 'Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php',
  3505. 'Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php',
  3506. 'Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php',
  3507. 'Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php',
  3508. 'Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php',
  3509. 'Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => $vendorDir . '/symfony/console/Tester/CommandCompletionTester.php',
  3510. 'Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php',
  3511. 'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => $vendorDir . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php',
  3512. 'Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php',
  3513. 'Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener' => $vendorDir . '/symfony/event-dispatcher/Attribute/AsEventListener.php',
  3514. 'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
  3515. 'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => $vendorDir . '/symfony/event-dispatcher/Debug/WrappedListener.php',
  3516. 'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
  3517. 'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
  3518. 'Symfony\\Component\\EventDispatcher\\EventDispatcher' => $vendorDir . '/symfony/event-dispatcher/EventDispatcher.php',
  3519. 'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher/EventDispatcherInterface.php',
  3520. 'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => $vendorDir . '/symfony/event-dispatcher/EventSubscriberInterface.php',
  3521. 'Symfony\\Component\\EventDispatcher\\GenericEvent' => $vendorDir . '/symfony/event-dispatcher/GenericEvent.php',
  3522. 'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
  3523. 'Symfony\\Component\\EventDispatcher\\LegacyEventDispatcherProxy' => $vendorDir . '/symfony/event-dispatcher/LegacyEventDispatcherProxy.php',
  3524. 'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php',
  3525. 'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php',
  3526. 'Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php',
  3527. 'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/IOExceptionInterface.php',
  3528. 'Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/filesystem/Exception/InvalidArgumentException.php',
  3529. 'Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => $vendorDir . '/symfony/filesystem/Exception/RuntimeException.php',
  3530. 'Symfony\\Component\\Filesystem\\Filesystem' => $vendorDir . '/symfony/filesystem/Filesystem.php',
  3531. 'Symfony\\Component\\Filesystem\\Path' => $vendorDir . '/symfony/filesystem/Path.php',
  3532. 'Symfony\\Component\\Finder\\Comparator\\Comparator' => $vendorDir . '/symfony/finder/Comparator/Comparator.php',
  3533. 'Symfony\\Component\\Finder\\Comparator\\DateComparator' => $vendorDir . '/symfony/finder/Comparator/DateComparator.php',
  3534. 'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => $vendorDir . '/symfony/finder/Comparator/NumberComparator.php',
  3535. 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => $vendorDir . '/symfony/finder/Exception/AccessDeniedException.php',
  3536. 'Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => $vendorDir . '/symfony/finder/Exception/DirectoryNotFoundException.php',
  3537. 'Symfony\\Component\\Finder\\Finder' => $vendorDir . '/symfony/finder/Finder.php',
  3538. 'Symfony\\Component\\Finder\\Gitignore' => $vendorDir . '/symfony/finder/Gitignore.php',
  3539. 'Symfony\\Component\\Finder\\Glob' => $vendorDir . '/symfony/finder/Glob.php',
  3540. 'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => $vendorDir . '/symfony/finder/Iterator/CustomFilterIterator.php',
  3541. 'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
  3542. 'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
  3543. 'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => $vendorDir . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
  3544. 'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
  3545. 'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
  3546. 'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilenameFilterIterator.php',
  3547. 'Symfony\\Component\\Finder\\Iterator\\LazyIterator' => $vendorDir . '/symfony/finder/Iterator/LazyIterator.php',
  3548. 'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => $vendorDir . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
  3549. 'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => $vendorDir . '/symfony/finder/Iterator/PathFilterIterator.php',
  3550. 'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => $vendorDir . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
  3551. 'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
  3552. 'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => $vendorDir . '/symfony/finder/Iterator/SortableIterator.php',
  3553. 'Symfony\\Component\\Finder\\Iterator\\VcsIgnoredFilterIterator' => $vendorDir . '/symfony/finder/Iterator/VcsIgnoredFilterIterator.php',
  3554. 'Symfony\\Component\\Finder\\SplFileInfo' => $vendorDir . '/symfony/finder/SplFileInfo.php',
  3555. 'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => $vendorDir . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
  3556. 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => $vendorDir . '/symfony/options-resolver/Exception/AccessException.php',
  3557. 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/options-resolver/Exception/ExceptionInterface.php',
  3558. 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
  3559. 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
  3560. 'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/MissingOptionsException.php',
  3561. 'Symfony\\Component\\OptionsResolver\\Exception\\NoConfigurationException' => $vendorDir . '/symfony/options-resolver/Exception/NoConfigurationException.php',
  3562. 'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => $vendorDir . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
  3563. 'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => $vendorDir . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
  3564. 'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
  3565. 'Symfony\\Component\\OptionsResolver\\OptionConfigurator' => $vendorDir . '/symfony/options-resolver/OptionConfigurator.php',
  3566. 'Symfony\\Component\\OptionsResolver\\Options' => $vendorDir . '/symfony/options-resolver/Options.php',
  3567. 'Symfony\\Component\\OptionsResolver\\OptionsResolver' => $vendorDir . '/symfony/options-resolver/OptionsResolver.php',
  3568. 'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php',
  3569. 'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php',
  3570. 'Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php',
  3571. 'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
  3572. 'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php',
  3573. 'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
  3574. 'Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
  3575. 'Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
  3576. 'Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php',
  3577. 'Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
  3578. 'Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
  3579. 'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
  3580. 'Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
  3581. 'Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',
  3582. 'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php',
  3583. 'Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php',
  3584. 'Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php',
  3585. 'Symfony\\Component\\Stopwatch\\Section' => $vendorDir . '/symfony/stopwatch/Section.php',
  3586. 'Symfony\\Component\\Stopwatch\\Stopwatch' => $vendorDir . '/symfony/stopwatch/Stopwatch.php',
  3587. 'Symfony\\Component\\Stopwatch\\StopwatchEvent' => $vendorDir . '/symfony/stopwatch/StopwatchEvent.php',
  3588. 'Symfony\\Component\\Stopwatch\\StopwatchPeriod' => $vendorDir . '/symfony/stopwatch/StopwatchPeriod.php',
  3589. 'Symfony\\Component\\String\\AbstractString' => $vendorDir . '/symfony/string/AbstractString.php',
  3590. 'Symfony\\Component\\String\\AbstractUnicodeString' => $vendorDir . '/symfony/string/AbstractUnicodeString.php',
  3591. 'Symfony\\Component\\String\\ByteString' => $vendorDir . '/symfony/string/ByteString.php',
  3592. 'Symfony\\Component\\String\\CodePointString' => $vendorDir . '/symfony/string/CodePointString.php',
  3593. 'Symfony\\Component\\String\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/string/Exception/ExceptionInterface.php',
  3594. 'Symfony\\Component\\String\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/string/Exception/InvalidArgumentException.php',
  3595. 'Symfony\\Component\\String\\Exception\\RuntimeException' => $vendorDir . '/symfony/string/Exception/RuntimeException.php',
  3596. 'Symfony\\Component\\String\\Inflector\\EnglishInflector' => $vendorDir . '/symfony/string/Inflector/EnglishInflector.php',
  3597. 'Symfony\\Component\\String\\Inflector\\FrenchInflector' => $vendorDir . '/symfony/string/Inflector/FrenchInflector.php',
  3598. 'Symfony\\Component\\String\\Inflector\\InflectorInterface' => $vendorDir . '/symfony/string/Inflector/InflectorInterface.php',
  3599. 'Symfony\\Component\\String\\LazyString' => $vendorDir . '/symfony/string/LazyString.php',
  3600. 'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php',
  3601. 'Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php',
  3602. 'Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php',
  3603. 'Symfony\\Contracts\\EventDispatcher\\Event' => $vendorDir . '/symfony/event-dispatcher-contracts/Event.php',
  3604. 'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
  3605. 'Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php',
  3606. 'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php',
  3607. 'Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
  3608. 'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
  3609. 'Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
  3610. 'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
  3611. 'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
  3612. 'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => $vendorDir . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
  3613. 'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTestCase' => $vendorDir . '/symfony/service-contracts/Test/ServiceLocatorTestCase.php',
  3614. 'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
  3615. 'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => $vendorDir . '/symfony/polyfill-intl-grapheme/Grapheme.php',
  3616. 'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
  3617. 'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
  3618. 'Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php',
  3619. 'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
  3620. 'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',
  3621. 'Symfony\\Polyfill\\Php81\\Php81' => $vendorDir . '/symfony/polyfill-php81/Php81.php',
  3622. 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
  3623. 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
  3624. );
  3625. <?php
  3626. $issues = array();
  3627. if (!(PHP_VERSION_ID >= 70400)) {
  3628. $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
  3629. }
  3630. if ($issues) {
  3631. if (!headers_sent()) {
  3632. header('HTTP/1.1 500 Internal Server Error');
  3633. }
  3634. if (!ini_get('display_errors')) {
  3635. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  3636. fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
  3637. } elseif (!headers_sent()) {
  3638. echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
  3639. }
  3640. }
  3641. trigger_error(
  3642. 'Composer detected issues in your platform: ' . implode(' ', $issues),
  3643. E_USER_ERROR
  3644. );
  3645. }
  3646. <?php
  3647. namespace Composer\Autoload;
  3648. class ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd
  3649. {
  3650. public static $files = array (
  3651. 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
  3652. '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
  3653. 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
  3654. '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
  3655. '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
  3656. '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
  3657. 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
  3658. '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
  3659. 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
  3660. '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
  3661. );
  3662. public static $prefixLengthsPsr4 = array (
  3663. 'S' =>
  3664. array (
  3665. 'Symfony\\Polyfill\\Php81\\' => 23,
  3666. 'Symfony\\Polyfill\\Php80\\' => 23,
  3667. 'Symfony\\Polyfill\\Php73\\' => 23,
  3668. 'Symfony\\Polyfill\\Mbstring\\' => 26,
  3669. 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
  3670. 'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31,
  3671. 'Symfony\\Polyfill\\Ctype\\' => 23,
  3672. 'Symfony\\Contracts\\Service\\' => 26,
  3673. 'Symfony\\Contracts\\EventDispatcher\\' => 34,
  3674. 'Symfony\\Component\\String\\' => 25,
  3675. 'Symfony\\Component\\Stopwatch\\' => 28,
  3676. 'Symfony\\Component\\Process\\' => 26,
  3677. 'Symfony\\Component\\OptionsResolver\\' => 34,
  3678. 'Symfony\\Component\\Finder\\' => 25,
  3679. 'Symfony\\Component\\Filesystem\\' => 29,
  3680. 'Symfony\\Component\\EventDispatcher\\' => 34,
  3681. 'Symfony\\Component\\Console\\' => 26,
  3682. ),
  3683. 'R' =>
  3684. array (
  3685. 'React\\Stream\\' => 13,
  3686. 'React\\Socket\\' => 13,
  3687. 'React\\Promise\\' => 14,
  3688. 'React\\EventLoop\\' => 16,
  3689. 'React\\Dns\\' => 10,
  3690. 'React\\ChildProcess\\' => 19,
  3691. 'React\\Cache\\' => 12,
  3692. ),
  3693. 'P' =>
  3694. array (
  3695. 'Psr\\Log\\' => 8,
  3696. 'Psr\\EventDispatcher\\' => 20,
  3697. 'Psr\\Container\\' => 14,
  3698. 'PhpCsFixer\\' => 11,
  3699. ),
  3700. 'F' =>
  3701. array (
  3702. 'Fidry\\CpuCoreCounter\\' => 21,
  3703. ),
  3704. 'E' =>
  3705. array (
  3706. 'Evenement\\' => 10,
  3707. ),
  3708. 'C' =>
  3709. array (
  3710. 'Composer\\XdebugHandler\\' => 23,
  3711. 'Composer\\Semver\\' => 16,
  3712. 'Composer\\Pcre\\' => 14,
  3713. 'Clue\\React\\NDJson\\' => 18,
  3714. ),
  3715. );
  3716. public static $prefixDirsPsr4 = array (
  3717. 'Symfony\\Polyfill\\Php81\\' =>
  3718. array (
  3719. 0 => __DIR__ . '/..' . '/symfony/polyfill-php81',
  3720. ),
  3721. 'Symfony\\Polyfill\\Php80\\' =>
  3722. array (
  3723. 0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
  3724. ),
  3725. 'Symfony\\Polyfill\\Php73\\' =>
  3726. array (
  3727. 0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
  3728. ),
  3729. 'Symfony\\Polyfill\\Mbstring\\' =>
  3730. array (
  3731. 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
  3732. ),
  3733. 'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
  3734. array (
  3735. 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
  3736. ),
  3737. 'Symfony\\Polyfill\\Intl\\Grapheme\\' =>
  3738. array (
  3739. 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme',
  3740. ),
  3741. 'Symfony\\Polyfill\\Ctype\\' =>
  3742. array (
  3743. 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
  3744. ),
  3745. 'Symfony\\Contracts\\Service\\' =>
  3746. array (
  3747. 0 => __DIR__ . '/..' . '/symfony/service-contracts',
  3748. ),
  3749. 'Symfony\\Contracts\\EventDispatcher\\' =>
  3750. array (
  3751. 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts',
  3752. ),
  3753. 'Symfony\\Component\\String\\' =>
  3754. array (
  3755. 0 => __DIR__ . '/..' . '/symfony/string',
  3756. ),
  3757. 'Symfony\\Component\\Stopwatch\\' =>
  3758. array (
  3759. 0 => __DIR__ . '/..' . '/symfony/stopwatch',
  3760. ),
  3761. 'Symfony\\Component\\Process\\' =>
  3762. array (
  3763. 0 => __DIR__ . '/..' . '/symfony/process',
  3764. ),
  3765. 'Symfony\\Component\\OptionsResolver\\' =>
  3766. array (
  3767. 0 => __DIR__ . '/..' . '/symfony/options-resolver',
  3768. ),
  3769. 'Symfony\\Component\\Finder\\' =>
  3770. array (
  3771. 0 => __DIR__ . '/..' . '/symfony/finder',
  3772. ),
  3773. 'Symfony\\Component\\Filesystem\\' =>
  3774. array (
  3775. 0 => __DIR__ . '/..' . '/symfony/filesystem',
  3776. ),
  3777. 'Symfony\\Component\\EventDispatcher\\' =>
  3778. array (
  3779. 0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
  3780. ),
  3781. 'Symfony\\Component\\Console\\' =>
  3782. array (
  3783. 0 => __DIR__ . '/..' . '/symfony/console',
  3784. ),
  3785. 'React\\Stream\\' =>
  3786. array (
  3787. 0 => __DIR__ . '/..' . '/react/stream/src',
  3788. ),
  3789. 'React\\Socket\\' =>
  3790. array (
  3791. 0 => __DIR__ . '/..' . '/react/socket/src',
  3792. ),
  3793. 'React\\Promise\\' =>
  3794. array (
  3795. 0 => __DIR__ . '/..' . '/react/promise/src',
  3796. ),
  3797. 'React\\EventLoop\\' =>
  3798. array (
  3799. 0 => __DIR__ . '/..' . '/react/event-loop/src',
  3800. ),
  3801. 'React\\Dns\\' =>
  3802. array (
  3803. 0 => __DIR__ . '/..' . '/react/dns/src',
  3804. ),
  3805. 'React\\ChildProcess\\' =>
  3806. array (
  3807. 0 => __DIR__ . '/..' . '/react/child-process/src',
  3808. ),
  3809. 'React\\Cache\\' =>
  3810. array (
  3811. 0 => __DIR__ . '/..' . '/react/cache/src',
  3812. ),
  3813. 'Psr\\Log\\' =>
  3814. array (
  3815. 0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
  3816. ),
  3817. 'Psr\\EventDispatcher\\' =>
  3818. array (
  3819. 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src',
  3820. ),
  3821. 'Psr\\Container\\' =>
  3822. array (
  3823. 0 => __DIR__ . '/..' . '/psr/container/src',
  3824. ),
  3825. 'PhpCsFixer\\' =>
  3826. array (
  3827. 0 => __DIR__ . '/../..' . '/src',
  3828. ),
  3829. 'Fidry\\CpuCoreCounter\\' =>
  3830. array (
  3831. 0 => __DIR__ . '/..' . '/fidry/cpu-core-counter/src',
  3832. ),
  3833. 'Evenement\\' =>
  3834. array (
  3835. 0 => __DIR__ . '/..' . '/evenement/evenement/src',
  3836. ),
  3837. 'Composer\\XdebugHandler\\' =>
  3838. array (
  3839. 0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
  3840. ),
  3841. 'Composer\\Semver\\' =>
  3842. array (
  3843. 0 => __DIR__ . '/..' . '/composer/semver/src',
  3844. ),
  3845. 'Composer\\Pcre\\' =>
  3846. array (
  3847. 0 => __DIR__ . '/..' . '/composer/pcre/src',
  3848. ),
  3849. 'Clue\\React\\NDJson\\' =>
  3850. array (
  3851. 0 => __DIR__ . '/..' . '/clue/ndjson-react/src',
  3852. ),
  3853. );
  3854. public static $classMap = array (
  3855. 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
  3856. 'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
  3857. 'Clue\\React\\NDJson\\Decoder' => __DIR__ . '/..' . '/clue/ndjson-react/src/Decoder.php',
  3858. 'Clue\\React\\NDJson\\Encoder' => __DIR__ . '/..' . '/clue/ndjson-react/src/Encoder.php',
  3859. 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
  3860. 'Composer\\Pcre\\MatchAllResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllResult.php',
  3861. 'Composer\\Pcre\\MatchAllStrictGroupsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllStrictGroupsResult.php',
  3862. 'Composer\\Pcre\\MatchAllWithOffsetsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllWithOffsetsResult.php',
  3863. 'Composer\\Pcre\\MatchResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchResult.php',
  3864. 'Composer\\Pcre\\MatchStrictGroupsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchStrictGroupsResult.php',
  3865. 'Composer\\Pcre\\MatchWithOffsetsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchWithOffsetsResult.php',
  3866. 'Composer\\Pcre\\PHPStan\\InvalidRegexPatternRule' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php',
  3867. 'Composer\\Pcre\\PHPStan\\PregMatchFlags' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchFlags.php',
  3868. 'Composer\\Pcre\\PHPStan\\PregMatchParameterOutTypeExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php',
  3869. 'Composer\\Pcre\\PHPStan\\PregMatchTypeSpecifyingExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php',
  3870. 'Composer\\Pcre\\PHPStan\\PregReplaceCallbackClosureTypeExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php',
  3871. 'Composer\\Pcre\\PHPStan\\UnsafeStrictGroupsCallRule' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php',
  3872. 'Composer\\Pcre\\PcreException' => __DIR__ . '/..' . '/composer/pcre/src/PcreException.php',
  3873. 'Composer\\Pcre\\Preg' => __DIR__ . '/..' . '/composer/pcre/src/Preg.php',
  3874. 'Composer\\Pcre\\Regex' => __DIR__ . '/..' . '/composer/pcre/src/Regex.php',
  3875. 'Composer\\Pcre\\ReplaceResult' => __DIR__ . '/..' . '/composer/pcre/src/ReplaceResult.php',
  3876. 'Composer\\Pcre\\UnexpectedNullMatchException' => __DIR__ . '/..' . '/composer/pcre/src/UnexpectedNullMatchException.php',
  3877. 'Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php',
  3878. 'Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php',
  3879. 'Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php',
  3880. 'Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php',
  3881. 'Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php',
  3882. 'Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php',
  3883. 'Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
  3884. 'Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php',
  3885. 'Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php',
  3886. 'Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php',
  3887. 'Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php',
  3888. 'Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php',
  3889. 'Composer\\XdebugHandler\\PhpConfig' => __DIR__ . '/..' . '/composer/xdebug-handler/src/PhpConfig.php',
  3890. 'Composer\\XdebugHandler\\Process' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Process.php',
  3891. 'Composer\\XdebugHandler\\Status' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Status.php',
  3892. 'Composer\\XdebugHandler\\XdebugHandler' => __DIR__ . '/..' . '/composer/xdebug-handler/src/XdebugHandler.php',
  3893. 'Evenement\\EventEmitter' => __DIR__ . '/..' . '/evenement/evenement/src/EventEmitter.php',
  3894. 'Evenement\\EventEmitterInterface' => __DIR__ . '/..' . '/evenement/evenement/src/EventEmitterInterface.php',
  3895. 'Evenement\\EventEmitterTrait' => __DIR__ . '/..' . '/evenement/evenement/src/EventEmitterTrait.php',
  3896. 'Fidry\\CpuCoreCounter\\CpuCoreCounter' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/CpuCoreCounter.php',
  3897. 'Fidry\\CpuCoreCounter\\Diagnoser' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Diagnoser.php',
  3898. 'Fidry\\CpuCoreCounter\\Executor\\ProcOpenExecutor' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.php',
  3899. 'Fidry\\CpuCoreCounter\\Executor\\ProcessExecutor' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Executor/ProcessExecutor.php',
  3900. 'Fidry\\CpuCoreCounter\\Finder\\CmiCmdletLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.php',
  3901. 'Fidry\\CpuCoreCounter\\Finder\\CmiCmdletPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.php',
  3902. 'Fidry\\CpuCoreCounter\\Finder\\CpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.php',
  3903. 'Fidry\\CpuCoreCounter\\Finder\\CpuInfoFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.php',
  3904. 'Fidry\\CpuCoreCounter\\Finder\\DummyCpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.php',
  3905. 'Fidry\\CpuCoreCounter\\Finder\\EnvVariableFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.php',
  3906. 'Fidry\\CpuCoreCounter\\Finder\\FinderRegistry' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/FinderRegistry.php',
  3907. 'Fidry\\CpuCoreCounter\\Finder\\HwLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.php',
  3908. 'Fidry\\CpuCoreCounter\\Finder\\HwPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php',
  3909. 'Fidry\\CpuCoreCounter\\Finder\\LscpuLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.php',
  3910. 'Fidry\\CpuCoreCounter\\Finder\\LscpuPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.php',
  3911. 'Fidry\\CpuCoreCounter\\Finder\\NProcFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NProcFinder.php',
  3912. 'Fidry\\CpuCoreCounter\\Finder\\NProcessorFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NProcessorFinder.php',
  3913. 'Fidry\\CpuCoreCounter\\Finder\\NullCpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.php',
  3914. 'Fidry\\CpuCoreCounter\\Finder\\OnlyInPowerShellFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.php',
  3915. 'Fidry\\CpuCoreCounter\\Finder\\OnlyOnOSFamilyFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.php',
  3916. 'Fidry\\CpuCoreCounter\\Finder\\ProcOpenBasedFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.php',
  3917. 'Fidry\\CpuCoreCounter\\Finder\\SkipOnOSFamilyFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.php',
  3918. 'Fidry\\CpuCoreCounter\\Finder\\WindowsRegistryLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php',
  3919. 'Fidry\\CpuCoreCounter\\Finder\\WmicLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.php',
  3920. 'Fidry\\CpuCoreCounter\\Finder\\WmicPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.php',
  3921. 'Fidry\\CpuCoreCounter\\Finder\\_NProcessorFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.php',
  3922. 'Fidry\\CpuCoreCounter\\NumberOfCpuCoreNotFound' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php',
  3923. 'Fidry\\CpuCoreCounter\\ParallelisationResult' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/ParallelisationResult.php',
  3924. 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
  3925. 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
  3926. 'PhpCsFixer\\AbstractDoctrineAnnotationFixer' => __DIR__ . '/../..' . '/src/AbstractDoctrineAnnotationFixer.php',
  3927. 'PhpCsFixer\\AbstractFixer' => __DIR__ . '/../..' . '/src/AbstractFixer.php',
  3928. 'PhpCsFixer\\AbstractFopenFlagFixer' => __DIR__ . '/../..' . '/src/AbstractFopenFlagFixer.php',
  3929. 'PhpCsFixer\\AbstractFunctionReferenceFixer' => __DIR__ . '/../..' . '/src/AbstractFunctionReferenceFixer.php',
  3930. 'PhpCsFixer\\AbstractNoUselessElseFixer' => __DIR__ . '/../..' . '/src/AbstractNoUselessElseFixer.php',
  3931. 'PhpCsFixer\\AbstractPhpdocToTypeDeclarationFixer' => __DIR__ . '/../..' . '/src/AbstractPhpdocToTypeDeclarationFixer.php',
  3932. 'PhpCsFixer\\AbstractPhpdocTypesFixer' => __DIR__ . '/../..' . '/src/AbstractPhpdocTypesFixer.php',
  3933. 'PhpCsFixer\\AbstractProxyFixer' => __DIR__ . '/../..' . '/src/AbstractProxyFixer.php',
  3934. 'PhpCsFixer\\Cache\\Cache' => __DIR__ . '/../..' . '/src/Cache/Cache.php',
  3935. 'PhpCsFixer\\Cache\\CacheInterface' => __DIR__ . '/../..' . '/src/Cache/CacheInterface.php',
  3936. 'PhpCsFixer\\Cache\\CacheManagerInterface' => __DIR__ . '/../..' . '/src/Cache/CacheManagerInterface.php',
  3937. 'PhpCsFixer\\Cache\\Directory' => __DIR__ . '/../..' . '/src/Cache/Directory.php',
  3938. 'PhpCsFixer\\Cache\\DirectoryInterface' => __DIR__ . '/../..' . '/src/Cache/DirectoryInterface.php',
  3939. 'PhpCsFixer\\Cache\\FileCacheManager' => __DIR__ . '/../..' . '/src/Cache/FileCacheManager.php',
  3940. 'PhpCsFixer\\Cache\\FileHandler' => __DIR__ . '/../..' . '/src/Cache/FileHandler.php',
  3941. 'PhpCsFixer\\Cache\\FileHandlerInterface' => __DIR__ . '/../..' . '/src/Cache/FileHandlerInterface.php',
  3942. 'PhpCsFixer\\Cache\\NullCacheManager' => __DIR__ . '/../..' . '/src/Cache/NullCacheManager.php',
  3943. 'PhpCsFixer\\Cache\\Signature' => __DIR__ . '/../..' . '/src/Cache/Signature.php',
  3944. 'PhpCsFixer\\Cache\\SignatureInterface' => __DIR__ . '/../..' . '/src/Cache/SignatureInterface.php',
  3945. 'PhpCsFixer\\Config' => __DIR__ . '/../..' . '/src/Config.php',
  3946. 'PhpCsFixer\\ConfigInterface' => __DIR__ . '/../..' . '/src/ConfigInterface.php',
  3947. 'PhpCsFixer\\ConfigurationException\\InvalidConfigurationException' => __DIR__ . '/../..' . '/src/ConfigurationException/InvalidConfigurationException.php',
  3948. 'PhpCsFixer\\ConfigurationException\\InvalidFixerConfigurationException' => __DIR__ . '/../..' . '/src/ConfigurationException/InvalidFixerConfigurationException.php',
  3949. 'PhpCsFixer\\ConfigurationException\\InvalidForEnvFixerConfigurationException' => __DIR__ . '/../..' . '/src/ConfigurationException/InvalidForEnvFixerConfigurationException.php',
  3950. 'PhpCsFixer\\ConfigurationException\\RequiredFixerConfigurationException' => __DIR__ . '/../..' . '/src/ConfigurationException/RequiredFixerConfigurationException.php',
  3951. 'PhpCsFixer\\Console\\Application' => __DIR__ . '/../..' . '/src/Console/Application.php',
  3952. 'PhpCsFixer\\Console\\Command\\CheckCommand' => __DIR__ . '/../..' . '/src/Console/Command/CheckCommand.php',
  3953. 'PhpCsFixer\\Console\\Command\\DescribeCommand' => __DIR__ . '/../..' . '/src/Console/Command/DescribeCommand.php',
  3954. 'PhpCsFixer\\Console\\Command\\DescribeNameNotFoundException' => __DIR__ . '/../..' . '/src/Console/Command/DescribeNameNotFoundException.php',
  3955. 'PhpCsFixer\\Console\\Command\\DocumentationCommand' => __DIR__ . '/../..' . '/src/Console/Command/DocumentationCommand.php',
  3956. 'PhpCsFixer\\Console\\Command\\FixCommand' => __DIR__ . '/../..' . '/src/Console/Command/FixCommand.php',
  3957. 'PhpCsFixer\\Console\\Command\\FixCommandExitStatusCalculator' => __DIR__ . '/../..' . '/src/Console/Command/FixCommandExitStatusCalculator.php',
  3958. 'PhpCsFixer\\Console\\Command\\HelpCommand' => __DIR__ . '/../..' . '/src/Console/Command/HelpCommand.php',
  3959. 'PhpCsFixer\\Console\\Command\\ListFilesCommand' => __DIR__ . '/../..' . '/src/Console/Command/ListFilesCommand.php',
  3960. 'PhpCsFixer\\Console\\Command\\ListSetsCommand' => __DIR__ . '/../..' . '/src/Console/Command/ListSetsCommand.php',
  3961. 'PhpCsFixer\\Console\\Command\\SelfUpdateCommand' => __DIR__ . '/../..' . '/src/Console/Command/SelfUpdateCommand.php',
  3962. 'PhpCsFixer\\Console\\Command\\WorkerCommand' => __DIR__ . '/../..' . '/src/Console/Command/WorkerCommand.php',
  3963. 'PhpCsFixer\\Console\\ConfigurationResolver' => __DIR__ . '/../..' . '/src/Console/ConfigurationResolver.php',
  3964. 'PhpCsFixer\\Console\\Output\\ErrorOutput' => __DIR__ . '/../..' . '/src/Console/Output/ErrorOutput.php',
  3965. 'PhpCsFixer\\Console\\Output\\OutputContext' => __DIR__ . '/../..' . '/src/Console/Output/OutputContext.php',
  3966. 'PhpCsFixer\\Console\\Output\\Progress\\DotsOutput' => __DIR__ . '/../..' . '/src/Console/Output/Progress/DotsOutput.php',
  3967. 'PhpCsFixer\\Console\\Output\\Progress\\NullOutput' => __DIR__ . '/../..' . '/src/Console/Output/Progress/NullOutput.php',
  3968. 'PhpCsFixer\\Console\\Output\\Progress\\PercentageBarOutput' => __DIR__ . '/../..' . '/src/Console/Output/Progress/PercentageBarOutput.php',
  3969. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputFactory' => __DIR__ . '/../..' . '/src/Console/Output/Progress/ProgressOutputFactory.php',
  3970. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputInterface' => __DIR__ . '/../..' . '/src/Console/Output/Progress/ProgressOutputInterface.php',
  3971. 'PhpCsFixer\\Console\\Output\\Progress\\ProgressOutputType' => __DIR__ . '/../..' . '/src/Console/Output/Progress/ProgressOutputType.php',
  3972. 'PhpCsFixer\\Console\\Report\\FixReport\\CheckstyleReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/CheckstyleReporter.php',
  3973. 'PhpCsFixer\\Console\\Report\\FixReport\\GitlabReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/GitlabReporter.php',
  3974. 'PhpCsFixer\\Console\\Report\\FixReport\\JsonReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/JsonReporter.php',
  3975. 'PhpCsFixer\\Console\\Report\\FixReport\\JunitReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/JunitReporter.php',
  3976. 'PhpCsFixer\\Console\\Report\\FixReport\\ReportSummary' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/ReportSummary.php',
  3977. 'PhpCsFixer\\Console\\Report\\FixReport\\ReporterFactory' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/ReporterFactory.php',
  3978. 'PhpCsFixer\\Console\\Report\\FixReport\\ReporterInterface' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/ReporterInterface.php',
  3979. 'PhpCsFixer\\Console\\Report\\FixReport\\TextReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/TextReporter.php',
  3980. 'PhpCsFixer\\Console\\Report\\FixReport\\XmlReporter' => __DIR__ . '/../..' . '/src/Console/Report/FixReport/XmlReporter.php',
  3981. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\JsonReporter' => __DIR__ . '/../..' . '/src/Console/Report/ListSetsReport/JsonReporter.php',
  3982. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReportSummary' => __DIR__ . '/../..' . '/src/Console/Report/ListSetsReport/ReportSummary.php',
  3983. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReporterFactory' => __DIR__ . '/../..' . '/src/Console/Report/ListSetsReport/ReporterFactory.php',
  3984. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\ReporterInterface' => __DIR__ . '/../..' . '/src/Console/Report/ListSetsReport/ReporterInterface.php',
  3985. 'PhpCsFixer\\Console\\Report\\ListSetsReport\\TextReporter' => __DIR__ . '/../..' . '/src/Console/Report/ListSetsReport/TextReporter.php',
  3986. 'PhpCsFixer\\Console\\SelfUpdate\\GithubClient' => __DIR__ . '/../..' . '/src/Console/SelfUpdate/GithubClient.php',
  3987. 'PhpCsFixer\\Console\\SelfUpdate\\GithubClientInterface' => __DIR__ . '/../..' . '/src/Console/SelfUpdate/GithubClientInterface.php',
  3988. 'PhpCsFixer\\Console\\SelfUpdate\\NewVersionChecker' => __DIR__ . '/../..' . '/src/Console/SelfUpdate/NewVersionChecker.php',
  3989. 'PhpCsFixer\\Console\\SelfUpdate\\NewVersionCheckerInterface' => __DIR__ . '/../..' . '/src/Console/SelfUpdate/NewVersionCheckerInterface.php',
  3990. 'PhpCsFixer\\Console\\WarningsDetector' => __DIR__ . '/../..' . '/src/Console/WarningsDetector.php',
  3991. 'PhpCsFixer\\Differ\\DiffConsoleFormatter' => __DIR__ . '/../..' . '/src/Differ/DiffConsoleFormatter.php',
  3992. 'PhpCsFixer\\Differ\\DifferInterface' => __DIR__ . '/../..' . '/src/Differ/DifferInterface.php',
  3993. 'PhpCsFixer\\Differ\\FullDiffer' => __DIR__ . '/../..' . '/src/Differ/FullDiffer.php',
  3994. 'PhpCsFixer\\Differ\\NullDiffer' => __DIR__ . '/../..' . '/src/Differ/NullDiffer.php',
  3995. 'PhpCsFixer\\Differ\\UnifiedDiffer' => __DIR__ . '/../..' . '/src/Differ/UnifiedDiffer.php',
  3996. 'PhpCsFixer\\DocBlock\\Annotation' => __DIR__ . '/../..' . '/src/DocBlock/Annotation.php',
  3997. 'PhpCsFixer\\DocBlock\\DocBlock' => __DIR__ . '/../..' . '/src/DocBlock/DocBlock.php',
  3998. 'PhpCsFixer\\DocBlock\\Line' => __DIR__ . '/../..' . '/src/DocBlock/Line.php',
  3999. 'PhpCsFixer\\DocBlock\\ShortDescription' => __DIR__ . '/../..' . '/src/DocBlock/ShortDescription.php',
  4000. 'PhpCsFixer\\DocBlock\\Tag' => __DIR__ . '/../..' . '/src/DocBlock/Tag.php',
  4001. 'PhpCsFixer\\DocBlock\\TagComparator' => __DIR__ . '/../..' . '/src/DocBlock/TagComparator.php',
  4002. 'PhpCsFixer\\DocBlock\\TypeExpression' => __DIR__ . '/../..' . '/src/DocBlock/TypeExpression.php',
  4003. 'PhpCsFixer\\Doctrine\\Annotation\\DocLexer' => __DIR__ . '/../..' . '/src/Doctrine/Annotation/DocLexer.php',
  4004. 'PhpCsFixer\\Doctrine\\Annotation\\Token' => __DIR__ . '/../..' . '/src/Doctrine/Annotation/Token.php',
  4005. 'PhpCsFixer\\Doctrine\\Annotation\\Tokens' => __DIR__ . '/../..' . '/src/Doctrine/Annotation/Tokens.php',
  4006. 'PhpCsFixer\\Documentation\\DocumentationLocator' => __DIR__ . '/../..' . '/src/Documentation/DocumentationLocator.php',
  4007. 'PhpCsFixer\\Documentation\\FixerDocumentGenerator' => __DIR__ . '/../..' . '/src/Documentation/FixerDocumentGenerator.php',
  4008. 'PhpCsFixer\\Documentation\\RstUtils' => __DIR__ . '/../..' . '/src/Documentation/RstUtils.php',
  4009. 'PhpCsFixer\\Documentation\\RuleSetDocumentationGenerator' => __DIR__ . '/../..' . '/src/Documentation/RuleSetDocumentationGenerator.php',
  4010. 'PhpCsFixer\\Error\\Error' => __DIR__ . '/../..' . '/src/Error/Error.php',
  4011. 'PhpCsFixer\\Error\\ErrorsManager' => __DIR__ . '/../..' . '/src/Error/ErrorsManager.php',
  4012. 'PhpCsFixer\\Error\\SourceExceptionFactory' => __DIR__ . '/../..' . '/src/Error/SourceExceptionFactory.php',
  4013. 'PhpCsFixer\\ExecutorWithoutErrorHandler' => __DIR__ . '/../..' . '/src/ExecutorWithoutErrorHandler.php',
  4014. 'PhpCsFixer\\ExecutorWithoutErrorHandlerException' => __DIR__ . '/../..' . '/src/ExecutorWithoutErrorHandlerException.php',
  4015. 'PhpCsFixer\\FileReader' => __DIR__ . '/../..' . '/src/FileReader.php',
  4016. 'PhpCsFixer\\FileRemoval' => __DIR__ . '/../..' . '/src/FileRemoval.php',
  4017. 'PhpCsFixer\\Finder' => __DIR__ . '/../..' . '/src/Finder.php',
  4018. 'PhpCsFixer\\FixerConfiguration\\AliasedFixerOption' => __DIR__ . '/../..' . '/src/FixerConfiguration/AliasedFixerOption.php',
  4019. 'PhpCsFixer\\FixerConfiguration\\AliasedFixerOptionBuilder' => __DIR__ . '/../..' . '/src/FixerConfiguration/AliasedFixerOptionBuilder.php',
  4020. 'PhpCsFixer\\FixerConfiguration\\AllowedValueSubset' => __DIR__ . '/../..' . '/src/FixerConfiguration/AllowedValueSubset.php',
  4021. 'PhpCsFixer\\FixerConfiguration\\DeprecatedFixerOption' => __DIR__ . '/../..' . '/src/FixerConfiguration/DeprecatedFixerOption.php',
  4022. 'PhpCsFixer\\FixerConfiguration\\DeprecatedFixerOptionInterface' => __DIR__ . '/../..' . '/src/FixerConfiguration/DeprecatedFixerOptionInterface.php',
  4023. 'PhpCsFixer\\FixerConfiguration\\FixerConfigurationResolver' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerConfigurationResolver.php',
  4024. 'PhpCsFixer\\FixerConfiguration\\FixerConfigurationResolverInterface' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerConfigurationResolverInterface.php',
  4025. 'PhpCsFixer\\FixerConfiguration\\FixerOption' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerOption.php',
  4026. 'PhpCsFixer\\FixerConfiguration\\FixerOptionBuilder' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerOptionBuilder.php',
  4027. 'PhpCsFixer\\FixerConfiguration\\FixerOptionInterface' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerOptionInterface.php',
  4028. 'PhpCsFixer\\FixerConfiguration\\FixerOptionSorter' => __DIR__ . '/../..' . '/src/FixerConfiguration/FixerOptionSorter.php',
  4029. 'PhpCsFixer\\FixerConfiguration\\InvalidOptionsForEnvException' => __DIR__ . '/../..' . '/src/FixerConfiguration/InvalidOptionsForEnvException.php',
  4030. 'PhpCsFixer\\FixerDefinition\\CodeSample' => __DIR__ . '/../..' . '/src/FixerDefinition/CodeSample.php',
  4031. 'PhpCsFixer\\FixerDefinition\\CodeSampleInterface' => __DIR__ . '/../..' . '/src/FixerDefinition/CodeSampleInterface.php',
  4032. 'PhpCsFixer\\FixerDefinition\\FileSpecificCodeSample' => __DIR__ . '/../..' . '/src/FixerDefinition/FileSpecificCodeSample.php',
  4033. 'PhpCsFixer\\FixerDefinition\\FileSpecificCodeSampleInterface' => __DIR__ . '/../..' . '/src/FixerDefinition/FileSpecificCodeSampleInterface.php',
  4034. 'PhpCsFixer\\FixerDefinition\\FixerDefinition' => __DIR__ . '/../..' . '/src/FixerDefinition/FixerDefinition.php',
  4035. 'PhpCsFixer\\FixerDefinition\\FixerDefinitionInterface' => __DIR__ . '/../..' . '/src/FixerDefinition/FixerDefinitionInterface.php',
  4036. 'PhpCsFixer\\FixerDefinition\\VersionSpecificCodeSample' => __DIR__ . '/../..' . '/src/FixerDefinition/VersionSpecificCodeSample.php',
  4037. 'PhpCsFixer\\FixerDefinition\\VersionSpecificCodeSampleInterface' => __DIR__ . '/../..' . '/src/FixerDefinition/VersionSpecificCodeSampleInterface.php',
  4038. 'PhpCsFixer\\FixerDefinition\\VersionSpecification' => __DIR__ . '/../..' . '/src/FixerDefinition/VersionSpecification.php',
  4039. 'PhpCsFixer\\FixerDefinition\\VersionSpecificationInterface' => __DIR__ . '/../..' . '/src/FixerDefinition/VersionSpecificationInterface.php',
  4040. 'PhpCsFixer\\FixerFactory' => __DIR__ . '/../..' . '/src/FixerFactory.php',
  4041. 'PhpCsFixer\\FixerNameValidator' => __DIR__ . '/../..' . '/src/FixerNameValidator.php',
  4042. 'PhpCsFixer\\Fixer\\AbstractIncrementOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/AbstractIncrementOperatorFixer.php',
  4043. 'PhpCsFixer\\Fixer\\AbstractPhpUnitFixer' => __DIR__ . '/../..' . '/src/Fixer/AbstractPhpUnitFixer.php',
  4044. 'PhpCsFixer\\Fixer\\AbstractShortOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/AbstractShortOperatorFixer.php',
  4045. 'PhpCsFixer\\Fixer\\Alias\\ArrayPushFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/ArrayPushFixer.php',
  4046. 'PhpCsFixer\\Fixer\\Alias\\BacktickToShellExecFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/BacktickToShellExecFixer.php',
  4047. 'PhpCsFixer\\Fixer\\Alias\\EregToPregFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/EregToPregFixer.php',
  4048. 'PhpCsFixer\\Fixer\\Alias\\MbStrFunctionsFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/MbStrFunctionsFixer.php',
  4049. 'PhpCsFixer\\Fixer\\Alias\\ModernizeStrposFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/ModernizeStrposFixer.php',
  4050. 'PhpCsFixer\\Fixer\\Alias\\NoAliasFunctionsFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/NoAliasFunctionsFixer.php',
  4051. 'PhpCsFixer\\Fixer\\Alias\\NoAliasLanguageConstructCallFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/NoAliasLanguageConstructCallFixer.php',
  4052. 'PhpCsFixer\\Fixer\\Alias\\NoMixedEchoPrintFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/NoMixedEchoPrintFixer.php',
  4053. 'PhpCsFixer\\Fixer\\Alias\\PowToExponentiationFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/PowToExponentiationFixer.php',
  4054. 'PhpCsFixer\\Fixer\\Alias\\RandomApiMigrationFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/RandomApiMigrationFixer.php',
  4055. 'PhpCsFixer\\Fixer\\Alias\\SetTypeToCastFixer' => __DIR__ . '/../..' . '/src/Fixer/Alias/SetTypeToCastFixer.php',
  4056. 'PhpCsFixer\\Fixer\\ArrayNotation\\ArraySyntaxFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/ArraySyntaxFixer.php',
  4057. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoMultilineWhitespaceAroundDoubleArrowFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/NoMultilineWhitespaceAroundDoubleArrowFixer.php',
  4058. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoTrailingCommaInSinglelineArrayFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/NoTrailingCommaInSinglelineArrayFixer.php',
  4059. 'PhpCsFixer\\Fixer\\ArrayNotation\\NoWhitespaceBeforeCommaInArrayFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/NoWhitespaceBeforeCommaInArrayFixer.php',
  4060. 'PhpCsFixer\\Fixer\\ArrayNotation\\NormalizeIndexBraceFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/NormalizeIndexBraceFixer.php',
  4061. 'PhpCsFixer\\Fixer\\ArrayNotation\\ReturnToYieldFromFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/ReturnToYieldFromFixer.php',
  4062. 'PhpCsFixer\\Fixer\\ArrayNotation\\TrimArraySpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/TrimArraySpacesFixer.php',
  4063. 'PhpCsFixer\\Fixer\\ArrayNotation\\WhitespaceAfterCommaInArrayFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/WhitespaceAfterCommaInArrayFixer.php',
  4064. 'PhpCsFixer\\Fixer\\ArrayNotation\\YieldFromArrayToYieldsFixer' => __DIR__ . '/../..' . '/src/Fixer/ArrayNotation/YieldFromArrayToYieldsFixer.php',
  4065. 'PhpCsFixer\\Fixer\\AttributeNotation\\AttributeEmptyParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/AttributeNotation/AttributeEmptyParenthesesFixer.php',
  4066. 'PhpCsFixer\\Fixer\\AttributeNotation\\GeneralAttributeRemoveFixer' => __DIR__ . '/../..' . '/src/Fixer/AttributeNotation/GeneralAttributeRemoveFixer.php',
  4067. 'PhpCsFixer\\Fixer\\AttributeNotation\\OrderedAttributesFixer' => __DIR__ . '/../..' . '/src/Fixer/AttributeNotation/OrderedAttributesFixer.php',
  4068. 'PhpCsFixer\\Fixer\\Basic\\BracesFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/BracesFixer.php',
  4069. 'PhpCsFixer\\Fixer\\Basic\\BracesPositionFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/BracesPositionFixer.php',
  4070. 'PhpCsFixer\\Fixer\\Basic\\CurlyBracesPositionFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/CurlyBracesPositionFixer.php',
  4071. 'PhpCsFixer\\Fixer\\Basic\\EncodingFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/EncodingFixer.php',
  4072. 'PhpCsFixer\\Fixer\\Basic\\NoMultipleStatementsPerLineFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/NoMultipleStatementsPerLineFixer.php',
  4073. 'PhpCsFixer\\Fixer\\Basic\\NoTrailingCommaInSinglelineFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/NoTrailingCommaInSinglelineFixer.php',
  4074. 'PhpCsFixer\\Fixer\\Basic\\NonPrintableCharacterFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/NonPrintableCharacterFixer.php',
  4075. 'PhpCsFixer\\Fixer\\Basic\\NumericLiteralSeparatorFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/NumericLiteralSeparatorFixer.php',
  4076. 'PhpCsFixer\\Fixer\\Basic\\OctalNotationFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/OctalNotationFixer.php',
  4077. 'PhpCsFixer\\Fixer\\Basic\\PsrAutoloadingFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/PsrAutoloadingFixer.php',
  4078. 'PhpCsFixer\\Fixer\\Basic\\SingleLineEmptyBodyFixer' => __DIR__ . '/../..' . '/src/Fixer/Basic/SingleLineEmptyBodyFixer.php',
  4079. 'PhpCsFixer\\Fixer\\Casing\\ClassReferenceNameCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/ClassReferenceNameCasingFixer.php',
  4080. 'PhpCsFixer\\Fixer\\Casing\\ConstantCaseFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/ConstantCaseFixer.php',
  4081. 'PhpCsFixer\\Fixer\\Casing\\IntegerLiteralCaseFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/IntegerLiteralCaseFixer.php',
  4082. 'PhpCsFixer\\Fixer\\Casing\\LowercaseKeywordsFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/LowercaseKeywordsFixer.php',
  4083. 'PhpCsFixer\\Fixer\\Casing\\LowercaseStaticReferenceFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/LowercaseStaticReferenceFixer.php',
  4084. 'PhpCsFixer\\Fixer\\Casing\\MagicConstantCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/MagicConstantCasingFixer.php',
  4085. 'PhpCsFixer\\Fixer\\Casing\\MagicMethodCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/MagicMethodCasingFixer.php',
  4086. 'PhpCsFixer\\Fixer\\Casing\\NativeFunctionCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/NativeFunctionCasingFixer.php',
  4087. 'PhpCsFixer\\Fixer\\Casing\\NativeFunctionTypeDeclarationCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/NativeFunctionTypeDeclarationCasingFixer.php',
  4088. 'PhpCsFixer\\Fixer\\Casing\\NativeTypeDeclarationCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php',
  4089. 'PhpCsFixer\\Fixer\\CastNotation\\CastSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/CastSpacesFixer.php',
  4090. 'PhpCsFixer\\Fixer\\CastNotation\\LowercaseCastFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/LowercaseCastFixer.php',
  4091. 'PhpCsFixer\\Fixer\\CastNotation\\ModernizeTypesCastingFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/ModernizeTypesCastingFixer.php',
  4092. 'PhpCsFixer\\Fixer\\CastNotation\\NoShortBoolCastFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/NoShortBoolCastFixer.php',
  4093. 'PhpCsFixer\\Fixer\\CastNotation\\NoUnsetCastFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/NoUnsetCastFixer.php',
  4094. 'PhpCsFixer\\Fixer\\CastNotation\\ShortScalarCastFixer' => __DIR__ . '/../..' . '/src/Fixer/CastNotation/ShortScalarCastFixer.php',
  4095. 'PhpCsFixer\\Fixer\\ClassNotation\\ClassAttributesSeparationFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php',
  4096. 'PhpCsFixer\\Fixer\\ClassNotation\\ClassDefinitionFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/ClassDefinitionFixer.php',
  4097. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalClassFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/FinalClassFixer.php',
  4098. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalInternalClassFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/FinalInternalClassFixer.php',
  4099. 'PhpCsFixer\\Fixer\\ClassNotation\\FinalPublicMethodForAbstractClassFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/FinalPublicMethodForAbstractClassFixer.php',
  4100. 'PhpCsFixer\\Fixer\\ClassNotation\\NoBlankLinesAfterClassOpeningFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixer.php',
  4101. 'PhpCsFixer\\Fixer\\ClassNotation\\NoNullPropertyInitializationFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/NoNullPropertyInitializationFixer.php',
  4102. 'PhpCsFixer\\Fixer\\ClassNotation\\NoPhp4ConstructorFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/NoPhp4ConstructorFixer.php',
  4103. 'PhpCsFixer\\Fixer\\ClassNotation\\NoUnneededFinalMethodFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/NoUnneededFinalMethodFixer.php',
  4104. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedClassElementsFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/OrderedClassElementsFixer.php',
  4105. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedInterfacesFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/OrderedInterfacesFixer.php',
  4106. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedTraitsFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/OrderedTraitsFixer.php',
  4107. 'PhpCsFixer\\Fixer\\ClassNotation\\OrderedTypesFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/OrderedTypesFixer.php',
  4108. 'PhpCsFixer\\Fixer\\ClassNotation\\PhpdocReadonlyClassCommentToKeywordFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/PhpdocReadonlyClassCommentToKeywordFixer.php',
  4109. 'PhpCsFixer\\Fixer\\ClassNotation\\ProtectedToPrivateFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/ProtectedToPrivateFixer.php',
  4110. 'PhpCsFixer\\Fixer\\ClassNotation\\SelfAccessorFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/SelfAccessorFixer.php',
  4111. 'PhpCsFixer\\Fixer\\ClassNotation\\SelfStaticAccessorFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/SelfStaticAccessorFixer.php',
  4112. 'PhpCsFixer\\Fixer\\ClassNotation\\SingleClassElementPerStatementFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/SingleClassElementPerStatementFixer.php',
  4113. 'PhpCsFixer\\Fixer\\ClassNotation\\SingleTraitInsertPerStatementFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php',
  4114. 'PhpCsFixer\\Fixer\\ClassNotation\\StaticPrivateMethodFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/StaticPrivateMethodFixer.php',
  4115. 'PhpCsFixer\\Fixer\\ClassNotation\\VisibilityRequiredFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassNotation/VisibilityRequiredFixer.php',
  4116. 'PhpCsFixer\\Fixer\\ClassUsage\\DateTimeImmutableFixer' => __DIR__ . '/../..' . '/src/Fixer/ClassUsage/DateTimeImmutableFixer.php',
  4117. 'PhpCsFixer\\Fixer\\Comment\\CommentToPhpdocFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/CommentToPhpdocFixer.php',
  4118. 'PhpCsFixer\\Fixer\\Comment\\HeaderCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/HeaderCommentFixer.php',
  4119. 'PhpCsFixer\\Fixer\\Comment\\MultilineCommentOpeningClosingFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/MultilineCommentOpeningClosingFixer.php',
  4120. 'PhpCsFixer\\Fixer\\Comment\\NoEmptyCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/NoEmptyCommentFixer.php',
  4121. 'PhpCsFixer\\Fixer\\Comment\\NoTrailingWhitespaceInCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/NoTrailingWhitespaceInCommentFixer.php',
  4122. 'PhpCsFixer\\Fixer\\Comment\\SingleLineCommentSpacingFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/SingleLineCommentSpacingFixer.php',
  4123. 'PhpCsFixer\\Fixer\\Comment\\SingleLineCommentStyleFixer' => __DIR__ . '/../..' . '/src/Fixer/Comment/SingleLineCommentStyleFixer.php',
  4124. 'PhpCsFixer\\Fixer\\ConfigurableFixerInterface' => __DIR__ . '/../..' . '/src/Fixer/ConfigurableFixerInterface.php',
  4125. 'PhpCsFixer\\Fixer\\ConfigurableFixerTrait' => __DIR__ . '/../..' . '/src/Fixer/ConfigurableFixerTrait.php',
  4126. 'PhpCsFixer\\Fixer\\ConstantNotation\\NativeConstantInvocationFixer' => __DIR__ . '/../..' . '/src/Fixer/ConstantNotation/NativeConstantInvocationFixer.php',
  4127. 'PhpCsFixer\\Fixer\\ControlStructure\\ControlStructureBracesFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/ControlStructureBracesFixer.php',
  4128. 'PhpCsFixer\\Fixer\\ControlStructure\\ControlStructureContinuationPositionFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/ControlStructureContinuationPositionFixer.php',
  4129. 'PhpCsFixer\\Fixer\\ControlStructure\\ElseifFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/ElseifFixer.php',
  4130. 'PhpCsFixer\\Fixer\\ControlStructure\\EmptyLoopBodyFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/EmptyLoopBodyFixer.php',
  4131. 'PhpCsFixer\\Fixer\\ControlStructure\\EmptyLoopConditionFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/EmptyLoopConditionFixer.php',
  4132. 'PhpCsFixer\\Fixer\\ControlStructure\\IncludeFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/IncludeFixer.php',
  4133. 'PhpCsFixer\\Fixer\\ControlStructure\\NoAlternativeSyntaxFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoAlternativeSyntaxFixer.php',
  4134. 'PhpCsFixer\\Fixer\\ControlStructure\\NoBreakCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoBreakCommentFixer.php',
  4135. 'PhpCsFixer\\Fixer\\ControlStructure\\NoSuperfluousElseifFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoSuperfluousElseifFixer.php',
  4136. 'PhpCsFixer\\Fixer\\ControlStructure\\NoTrailingCommaInListCallFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoTrailingCommaInListCallFixer.php',
  4137. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededBracesFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoUnneededBracesFixer.php',
  4138. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededControlParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoUnneededControlParenthesesFixer.php',
  4139. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededCurlyBracesFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoUnneededCurlyBracesFixer.php',
  4140. 'PhpCsFixer\\Fixer\\ControlStructure\\NoUselessElseFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/NoUselessElseFixer.php',
  4141. 'PhpCsFixer\\Fixer\\ControlStructure\\SimplifiedIfReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/SimplifiedIfReturnFixer.php',
  4142. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchCaseSemicolonToColonFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/SwitchCaseSemicolonToColonFixer.php',
  4143. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchCaseSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/SwitchCaseSpaceFixer.php',
  4144. 'PhpCsFixer\\Fixer\\ControlStructure\\SwitchContinueToBreakFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/SwitchContinueToBreakFixer.php',
  4145. 'PhpCsFixer\\Fixer\\ControlStructure\\TrailingCommaInMultilineFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/TrailingCommaInMultilineFixer.php',
  4146. 'PhpCsFixer\\Fixer\\ControlStructure\\YodaStyleFixer' => __DIR__ . '/../..' . '/src/Fixer/ControlStructure/YodaStyleFixer.php',
  4147. 'PhpCsFixer\\Fixer\\DeprecatedFixerInterface' => __DIR__ . '/../..' . '/src/Fixer/DeprecatedFixerInterface.php',
  4148. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationArrayAssignmentFixer' => __DIR__ . '/../..' . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationArrayAssignmentFixer.php',
  4149. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationBracesFixer' => __DIR__ . '/../..' . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixer.php',
  4150. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationIndentationFixer' => __DIR__ . '/../..' . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationIndentationFixer.php',
  4151. 'PhpCsFixer\\Fixer\\DoctrineAnnotation\\DoctrineAnnotationSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/DoctrineAnnotation/DoctrineAnnotationSpacesFixer.php',
  4152. 'PhpCsFixer\\Fixer\\ExperimentalFixerInterface' => __DIR__ . '/../..' . '/src/Fixer/ExperimentalFixerInterface.php',
  4153. 'PhpCsFixer\\Fixer\\FixerInterface' => __DIR__ . '/../..' . '/src/Fixer/FixerInterface.php',
  4154. 'PhpCsFixer\\Fixer\\FunctionNotation\\CombineNestedDirnameFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/CombineNestedDirnameFixer.php',
  4155. 'PhpCsFixer\\Fixer\\FunctionNotation\\DateTimeCreateFromFormatCallFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/DateTimeCreateFromFormatCallFixer.php',
  4156. 'PhpCsFixer\\Fixer\\FunctionNotation\\FopenFlagOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php',
  4157. 'PhpCsFixer\\Fixer\\FunctionNotation\\FopenFlagsFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/FopenFlagsFixer.php',
  4158. 'PhpCsFixer\\Fixer\\FunctionNotation\\FunctionDeclarationFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/FunctionDeclarationFixer.php',
  4159. 'PhpCsFixer\\Fixer\\FunctionNotation\\FunctionTypehintSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/FunctionTypehintSpaceFixer.php',
  4160. 'PhpCsFixer\\Fixer\\FunctionNotation\\ImplodeCallFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/ImplodeCallFixer.php',
  4161. 'PhpCsFixer\\Fixer\\FunctionNotation\\LambdaNotUsedImportFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/LambdaNotUsedImportFixer.php',
  4162. 'PhpCsFixer\\Fixer\\FunctionNotation\\MethodArgumentSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/MethodArgumentSpaceFixer.php',
  4163. 'PhpCsFixer\\Fixer\\FunctionNotation\\MultilinePromotedPropertiesFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/MultilinePromotedPropertiesFixer.php',
  4164. 'PhpCsFixer\\Fixer\\FunctionNotation\\NativeFunctionInvocationFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NativeFunctionInvocationFixer.php',
  4165. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoSpacesAfterFunctionNameFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php',
  4166. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoTrailingCommaInSinglelineFunctionCallFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NoTrailingCommaInSinglelineFunctionCallFixer.php',
  4167. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoUnreachableDefaultArgumentValueFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NoUnreachableDefaultArgumentValueFixer.php',
  4168. 'PhpCsFixer\\Fixer\\FunctionNotation\\NoUselessSprintfFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NoUselessSprintfFixer.php',
  4169. 'PhpCsFixer\\Fixer\\FunctionNotation\\NullableTypeDeclarationForDefaultNullValueFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/NullableTypeDeclarationForDefaultNullValueFixer.php',
  4170. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToParamTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php',
  4171. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToPropertyTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php',
  4172. 'PhpCsFixer\\Fixer\\FunctionNotation\\PhpdocToReturnTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php',
  4173. 'PhpCsFixer\\Fixer\\FunctionNotation\\RegularCallableCallFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/RegularCallableCallFixer.php',
  4174. 'PhpCsFixer\\Fixer\\FunctionNotation\\ReturnTypeDeclarationFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/ReturnTypeDeclarationFixer.php',
  4175. 'PhpCsFixer\\Fixer\\FunctionNotation\\SingleLineThrowFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/SingleLineThrowFixer.php',
  4176. 'PhpCsFixer\\Fixer\\FunctionNotation\\StaticLambdaFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/StaticLambdaFixer.php',
  4177. 'PhpCsFixer\\Fixer\\FunctionNotation\\UseArrowFunctionsFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php',
  4178. 'PhpCsFixer\\Fixer\\FunctionNotation\\VoidReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/FunctionNotation/VoidReturnFixer.php',
  4179. 'PhpCsFixer\\Fixer\\Import\\FullyQualifiedStrictTypesFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php',
  4180. 'PhpCsFixer\\Fixer\\Import\\GlobalNamespaceImportFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/GlobalNamespaceImportFixer.php',
  4181. 'PhpCsFixer\\Fixer\\Import\\GroupImportFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/GroupImportFixer.php',
  4182. 'PhpCsFixer\\Fixer\\Import\\NoLeadingImportSlashFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/NoLeadingImportSlashFixer.php',
  4183. 'PhpCsFixer\\Fixer\\Import\\NoUnneededImportAliasFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/NoUnneededImportAliasFixer.php',
  4184. 'PhpCsFixer\\Fixer\\Import\\NoUnusedImportsFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/NoUnusedImportsFixer.php',
  4185. 'PhpCsFixer\\Fixer\\Import\\OrderedImportsFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/OrderedImportsFixer.php',
  4186. 'PhpCsFixer\\Fixer\\Import\\SingleImportPerStatementFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/SingleImportPerStatementFixer.php',
  4187. 'PhpCsFixer\\Fixer\\Import\\SingleLineAfterImportsFixer' => __DIR__ . '/../..' . '/src/Fixer/Import/SingleLineAfterImportsFixer.php',
  4188. 'PhpCsFixer\\Fixer\\Indentation' => __DIR__ . '/../..' . '/src/Fixer/Indentation.php',
  4189. 'PhpCsFixer\\Fixer\\InternalFixerInterface' => __DIR__ . '/../..' . '/src/Fixer/InternalFixerInterface.php',
  4190. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ClassKeywordFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/ClassKeywordFixer.php',
  4191. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ClassKeywordRemoveFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/ClassKeywordRemoveFixer.php',
  4192. 'PhpCsFixer\\Fixer\\LanguageConstruct\\CombineConsecutiveIssetsFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php',
  4193. 'PhpCsFixer\\Fixer\\LanguageConstruct\\CombineConsecutiveUnsetsFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/CombineConsecutiveUnsetsFixer.php',
  4194. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DeclareEqualNormalizeFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/DeclareEqualNormalizeFixer.php',
  4195. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DeclareParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/DeclareParenthesesFixer.php',
  4196. 'PhpCsFixer\\Fixer\\LanguageConstruct\\DirConstantFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/DirConstantFixer.php',
  4197. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ErrorSuppressionFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/ErrorSuppressionFixer.php',
  4198. 'PhpCsFixer\\Fixer\\LanguageConstruct\\ExplicitIndirectVariableFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/ExplicitIndirectVariableFixer.php',
  4199. 'PhpCsFixer\\Fixer\\LanguageConstruct\\FunctionToConstantFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/FunctionToConstantFixer.php',
  4200. 'PhpCsFixer\\Fixer\\LanguageConstruct\\GetClassToClassKeywordFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/GetClassToClassKeywordFixer.php',
  4201. 'PhpCsFixer\\Fixer\\LanguageConstruct\\IsNullFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/IsNullFixer.php',
  4202. 'PhpCsFixer\\Fixer\\LanguageConstruct\\NoUnsetOnPropertyFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/NoUnsetOnPropertyFixer.php',
  4203. 'PhpCsFixer\\Fixer\\LanguageConstruct\\NullableTypeDeclarationFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/NullableTypeDeclarationFixer.php',
  4204. 'PhpCsFixer\\Fixer\\LanguageConstruct\\SingleSpaceAfterConstructFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/SingleSpaceAfterConstructFixer.php',
  4205. 'PhpCsFixer\\Fixer\\LanguageConstruct\\SingleSpaceAroundConstructFixer' => __DIR__ . '/../..' . '/src/Fixer/LanguageConstruct/SingleSpaceAroundConstructFixer.php',
  4206. 'PhpCsFixer\\Fixer\\ListNotation\\ListSyntaxFixer' => __DIR__ . '/../..' . '/src/Fixer/ListNotation/ListSyntaxFixer.php',
  4207. 'PhpCsFixer\\Fixer\\NamespaceNotation\\BlankLineAfterNamespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixer.php',
  4208. 'PhpCsFixer\\Fixer\\NamespaceNotation\\BlankLinesBeforeNamespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/BlankLinesBeforeNamespaceFixer.php',
  4209. 'PhpCsFixer\\Fixer\\NamespaceNotation\\CleanNamespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/CleanNamespaceFixer.php',
  4210. 'PhpCsFixer\\Fixer\\NamespaceNotation\\NoBlankLinesBeforeNamespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/NoBlankLinesBeforeNamespaceFixer.php',
  4211. 'PhpCsFixer\\Fixer\\NamespaceNotation\\NoLeadingNamespaceWhitespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/NoLeadingNamespaceWhitespaceFixer.php',
  4212. 'PhpCsFixer\\Fixer\\NamespaceNotation\\SingleBlankLineBeforeNamespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/NamespaceNotation/SingleBlankLineBeforeNamespaceFixer.php',
  4213. 'PhpCsFixer\\Fixer\\Naming\\NoHomoglyphNamesFixer' => __DIR__ . '/../..' . '/src/Fixer/Naming/NoHomoglyphNamesFixer.php',
  4214. 'PhpCsFixer\\Fixer\\Operator\\AssignNullCoalescingToCoalesceEqualFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/AssignNullCoalescingToCoalesceEqualFixer.php',
  4215. 'PhpCsFixer\\Fixer\\Operator\\BinaryOperatorSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/BinaryOperatorSpacesFixer.php',
  4216. 'PhpCsFixer\\Fixer\\Operator\\ConcatSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/ConcatSpaceFixer.php',
  4217. 'PhpCsFixer\\Fixer\\Operator\\IncrementStyleFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/IncrementStyleFixer.php',
  4218. 'PhpCsFixer\\Fixer\\Operator\\LogicalOperatorsFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/LogicalOperatorsFixer.php',
  4219. 'PhpCsFixer\\Fixer\\Operator\\LongToShorthandOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/LongToShorthandOperatorFixer.php',
  4220. 'PhpCsFixer\\Fixer\\Operator\\NewExpressionParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NewExpressionParenthesesFixer.php',
  4221. 'PhpCsFixer\\Fixer\\Operator\\NewWithBracesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NewWithBracesFixer.php',
  4222. 'PhpCsFixer\\Fixer\\Operator\\NewWithParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NewWithParenthesesFixer.php',
  4223. 'PhpCsFixer\\Fixer\\Operator\\NoSpaceAroundDoubleColonFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NoSpaceAroundDoubleColonFixer.php',
  4224. 'PhpCsFixer\\Fixer\\Operator\\NoUselessConcatOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NoUselessConcatOperatorFixer.php',
  4225. 'PhpCsFixer\\Fixer\\Operator\\NoUselessNullsafeOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NoUselessNullsafeOperatorFixer.php',
  4226. 'PhpCsFixer\\Fixer\\Operator\\NotOperatorWithSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NotOperatorWithSpaceFixer.php',
  4227. 'PhpCsFixer\\Fixer\\Operator\\NotOperatorWithSuccessorSpaceFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/NotOperatorWithSuccessorSpaceFixer.php',
  4228. 'PhpCsFixer\\Fixer\\Operator\\ObjectOperatorWithoutWhitespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/ObjectOperatorWithoutWhitespaceFixer.php',
  4229. 'PhpCsFixer\\Fixer\\Operator\\OperatorLinebreakFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/OperatorLinebreakFixer.php',
  4230. 'PhpCsFixer\\Fixer\\Operator\\StandardizeIncrementFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/StandardizeIncrementFixer.php',
  4231. 'PhpCsFixer\\Fixer\\Operator\\StandardizeNotEqualsFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/StandardizeNotEqualsFixer.php',
  4232. 'PhpCsFixer\\Fixer\\Operator\\TernaryOperatorSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/TernaryOperatorSpacesFixer.php',
  4233. 'PhpCsFixer\\Fixer\\Operator\\TernaryToElvisOperatorFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/TernaryToElvisOperatorFixer.php',
  4234. 'PhpCsFixer\\Fixer\\Operator\\TernaryToNullCoalescingFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/TernaryToNullCoalescingFixer.php',
  4235. 'PhpCsFixer\\Fixer\\Operator\\UnaryOperatorSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/Operator/UnaryOperatorSpacesFixer.php',
  4236. 'PhpCsFixer\\Fixer\\PhpTag\\BlankLineAfterOpeningTagFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpTag/BlankLineAfterOpeningTagFixer.php',
  4237. 'PhpCsFixer\\Fixer\\PhpTag\\EchoTagSyntaxFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpTag/EchoTagSyntaxFixer.php',
  4238. 'PhpCsFixer\\Fixer\\PhpTag\\FullOpeningTagFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpTag/FullOpeningTagFixer.php',
  4239. 'PhpCsFixer\\Fixer\\PhpTag\\LinebreakAfterOpeningTagFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpTag/LinebreakAfterOpeningTagFixer.php',
  4240. 'PhpCsFixer\\Fixer\\PhpTag\\NoClosingTagFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpTag/NoClosingTagFixer.php',
  4241. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitAssertNewNamesFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitAssertNewNamesFixer.php',
  4242. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitAttributesFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitAttributesFixer.php',
  4243. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitConstructFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitConstructFixer.php',
  4244. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderMethodOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDataProviderMethodOrderFixer.php',
  4245. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderNameFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDataProviderNameFixer.php',
  4246. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderReturnTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDataProviderReturnTypeFixer.php',
  4247. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDataProviderStaticFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDataProviderStaticFixer.php',
  4248. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDedicateAssertFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDedicateAssertFixer.php',
  4249. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitDedicateAssertInternalTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixer.php',
  4250. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitExpectationFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitExpectationFixer.php',
  4251. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitFqcnAnnotationFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixer.php',
  4252. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitInternalClassFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitInternalClassFixer.php',
  4253. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMethodCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitMethodCasingFixer.php',
  4254. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMockFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitMockFixer.php',
  4255. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitMockShortWillReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitMockShortWillReturnFixer.php',
  4256. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitNamespacedFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php',
  4257. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitNoExpectationAnnotationFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitNoExpectationAnnotationFixer.php',
  4258. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitSetUpTearDownVisibilityFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitSetUpTearDownVisibilityFixer.php',
  4259. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitSizeClassFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitSizeClassFixer.php',
  4260. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitStrictFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitStrictFixer.php',
  4261. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTargetVersion' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitTargetVersion.php',
  4262. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestAnnotationFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php',
  4263. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestCaseStaticMethodCallsFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php',
  4264. 'PhpCsFixer\\Fixer\\PhpUnit\\PhpUnitTestClassRequiresCoversFixer' => __DIR__ . '/../..' . '/src/Fixer/PhpUnit/PhpUnitTestClassRequiresCoversFixer.php',
  4265. 'PhpCsFixer\\Fixer\\Phpdoc\\AlignMultilineCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/AlignMultilineCommentFixer.php',
  4266. 'PhpCsFixer\\Fixer\\Phpdoc\\GeneralPhpdocAnnotationRemoveFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/GeneralPhpdocAnnotationRemoveFixer.php',
  4267. 'PhpCsFixer\\Fixer\\Phpdoc\\GeneralPhpdocTagRenameFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/GeneralPhpdocTagRenameFixer.php',
  4268. 'PhpCsFixer\\Fixer\\Phpdoc\\NoBlankLinesAfterPhpdocFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/NoBlankLinesAfterPhpdocFixer.php',
  4269. 'PhpCsFixer\\Fixer\\Phpdoc\\NoEmptyPhpdocFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/NoEmptyPhpdocFixer.php',
  4270. 'PhpCsFixer\\Fixer\\Phpdoc\\NoSuperfluousPhpdocTagsFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php',
  4271. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAddMissingParamAnnotationFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocAddMissingParamAnnotationFixer.php',
  4272. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAlignFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocAlignFixer.php',
  4273. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocAnnotationWithoutDotFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocAnnotationWithoutDotFixer.php',
  4274. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocArrayTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocArrayTypeFixer.php',
  4275. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocIndentFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocIndentFixer.php',
  4276. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocInlineTagNormalizerFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocInlineTagNormalizerFixer.php',
  4277. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocLineSpanFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocLineSpanFixer.php',
  4278. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocListTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocListTypeFixer.php',
  4279. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoAccessFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocNoAccessFixer.php',
  4280. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoAliasTagFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocNoAliasTagFixer.php',
  4281. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoEmptyReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocNoEmptyReturnFixer.php',
  4282. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoPackageFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocNoPackageFixer.php',
  4283. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocNoUselessInheritdocFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php',
  4284. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocOrderByValueFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocOrderByValueFixer.php',
  4285. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocOrderFixer.php',
  4286. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocParamOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php',
  4287. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocReturnSelfReferenceFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php',
  4288. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocScalarFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocScalarFixer.php',
  4289. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSeparationFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocSeparationFixer.php',
  4290. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSingleLineVarSpacingFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocSingleLineVarSpacingFixer.php',
  4291. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocSummaryFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocSummaryFixer.php',
  4292. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTagCasingFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTagCasingFixer.php',
  4293. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTagTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php',
  4294. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocToCommentFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocToCommentFixer.php',
  4295. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTrimConsecutiveBlankLineSeparationFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTrimConsecutiveBlankLineSeparationFixer.php',
  4296. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTrimFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTrimFixer.php',
  4297. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTypesFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTypesFixer.php',
  4298. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocTypesOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php',
  4299. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocVarAnnotationCorrectOrderFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocVarAnnotationCorrectOrderFixer.php',
  4300. 'PhpCsFixer\\Fixer\\Phpdoc\\PhpdocVarWithoutNameFixer' => __DIR__ . '/../..' . '/src/Fixer/Phpdoc/PhpdocVarWithoutNameFixer.php',
  4301. 'PhpCsFixer\\Fixer\\ReturnNotation\\NoUselessReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/ReturnNotation/NoUselessReturnFixer.php',
  4302. 'PhpCsFixer\\Fixer\\ReturnNotation\\ReturnAssignmentFixer' => __DIR__ . '/../..' . '/src/Fixer/ReturnNotation/ReturnAssignmentFixer.php',
  4303. 'PhpCsFixer\\Fixer\\ReturnNotation\\SimplifiedNullReturnFixer' => __DIR__ . '/../..' . '/src/Fixer/ReturnNotation/SimplifiedNullReturnFixer.php',
  4304. 'PhpCsFixer\\Fixer\\Semicolon\\MultilineWhitespaceBeforeSemicolonsFixer' => __DIR__ . '/../..' . '/src/Fixer/Semicolon/MultilineWhitespaceBeforeSemicolonsFixer.php',
  4305. 'PhpCsFixer\\Fixer\\Semicolon\\NoEmptyStatementFixer' => __DIR__ . '/../..' . '/src/Fixer/Semicolon/NoEmptyStatementFixer.php',
  4306. 'PhpCsFixer\\Fixer\\Semicolon\\NoSinglelineWhitespaceBeforeSemicolonsFixer' => __DIR__ . '/../..' . '/src/Fixer/Semicolon/NoSinglelineWhitespaceBeforeSemicolonsFixer.php',
  4307. 'PhpCsFixer\\Fixer\\Semicolon\\SemicolonAfterInstructionFixer' => __DIR__ . '/../..' . '/src/Fixer/Semicolon/SemicolonAfterInstructionFixer.php',
  4308. 'PhpCsFixer\\Fixer\\Semicolon\\SpaceAfterSemicolonFixer' => __DIR__ . '/../..' . '/src/Fixer/Semicolon/SpaceAfterSemicolonFixer.php',
  4309. 'PhpCsFixer\\Fixer\\Strict\\DeclareStrictTypesFixer' => __DIR__ . '/../..' . '/src/Fixer/Strict/DeclareStrictTypesFixer.php',
  4310. 'PhpCsFixer\\Fixer\\Strict\\StrictComparisonFixer' => __DIR__ . '/../..' . '/src/Fixer/Strict/StrictComparisonFixer.php',
  4311. 'PhpCsFixer\\Fixer\\Strict\\StrictParamFixer' => __DIR__ . '/../..' . '/src/Fixer/Strict/StrictParamFixer.php',
  4312. 'PhpCsFixer\\Fixer\\StringNotation\\EscapeImplicitBackslashesFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/EscapeImplicitBackslashesFixer.php',
  4313. 'PhpCsFixer\\Fixer\\StringNotation\\ExplicitStringVariableFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/ExplicitStringVariableFixer.php',
  4314. 'PhpCsFixer\\Fixer\\StringNotation\\HeredocClosingMarkerFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/HeredocClosingMarkerFixer.php',
  4315. 'PhpCsFixer\\Fixer\\StringNotation\\HeredocToNowdocFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/HeredocToNowdocFixer.php',
  4316. 'PhpCsFixer\\Fixer\\StringNotation\\MultilineStringToHeredocFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/MultilineStringToHeredocFixer.php',
  4317. 'PhpCsFixer\\Fixer\\StringNotation\\NoBinaryStringFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/NoBinaryStringFixer.php',
  4318. 'PhpCsFixer\\Fixer\\StringNotation\\NoTrailingWhitespaceInStringFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/NoTrailingWhitespaceInStringFixer.php',
  4319. 'PhpCsFixer\\Fixer\\StringNotation\\SimpleToComplexStringVariableFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/SimpleToComplexStringVariableFixer.php',
  4320. 'PhpCsFixer\\Fixer\\StringNotation\\SingleQuoteFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/SingleQuoteFixer.php',
  4321. 'PhpCsFixer\\Fixer\\StringNotation\\StringImplicitBackslashesFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/StringImplicitBackslashesFixer.php',
  4322. 'PhpCsFixer\\Fixer\\StringNotation\\StringLengthToEmptyFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/StringLengthToEmptyFixer.php',
  4323. 'PhpCsFixer\\Fixer\\StringNotation\\StringLineEndingFixer' => __DIR__ . '/../..' . '/src/Fixer/StringNotation/StringLineEndingFixer.php',
  4324. 'PhpCsFixer\\Fixer\\Whitespace\\ArrayIndentationFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/ArrayIndentationFixer.php',
  4325. 'PhpCsFixer\\Fixer\\Whitespace\\BlankLineBeforeStatementFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php',
  4326. 'PhpCsFixer\\Fixer\\Whitespace\\BlankLineBetweenImportGroupsFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/BlankLineBetweenImportGroupsFixer.php',
  4327. 'PhpCsFixer\\Fixer\\Whitespace\\CompactNullableTypeDeclarationFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/CompactNullableTypeDeclarationFixer.php',
  4328. 'PhpCsFixer\\Fixer\\Whitespace\\CompactNullableTypehintFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/CompactNullableTypehintFixer.php',
  4329. 'PhpCsFixer\\Fixer\\Whitespace\\HeredocIndentationFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/HeredocIndentationFixer.php',
  4330. 'PhpCsFixer\\Fixer\\Whitespace\\IndentationTypeFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/IndentationTypeFixer.php',
  4331. 'PhpCsFixer\\Fixer\\Whitespace\\LineEndingFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/LineEndingFixer.php',
  4332. 'PhpCsFixer\\Fixer\\Whitespace\\MethodChainingIndentationFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/MethodChainingIndentationFixer.php',
  4333. 'PhpCsFixer\\Fixer\\Whitespace\\NoExtraBlankLinesFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/NoExtraBlankLinesFixer.php',
  4334. 'PhpCsFixer\\Fixer\\Whitespace\\NoSpacesAroundOffsetFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/NoSpacesAroundOffsetFixer.php',
  4335. 'PhpCsFixer\\Fixer\\Whitespace\\NoSpacesInsideParenthesisFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/NoSpacesInsideParenthesisFixer.php',
  4336. 'PhpCsFixer\\Fixer\\Whitespace\\NoTrailingWhitespaceFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/NoTrailingWhitespaceFixer.php',
  4337. 'PhpCsFixer\\Fixer\\Whitespace\\NoWhitespaceInBlankLineFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/NoWhitespaceInBlankLineFixer.php',
  4338. 'PhpCsFixer\\Fixer\\Whitespace\\SingleBlankLineAtEofFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/SingleBlankLineAtEofFixer.php',
  4339. 'PhpCsFixer\\Fixer\\Whitespace\\SpacesInsideParenthesesFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/SpacesInsideParenthesesFixer.php',
  4340. 'PhpCsFixer\\Fixer\\Whitespace\\StatementIndentationFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/StatementIndentationFixer.php',
  4341. 'PhpCsFixer\\Fixer\\Whitespace\\TypeDeclarationSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/TypeDeclarationSpacesFixer.php',
  4342. 'PhpCsFixer\\Fixer\\Whitespace\\TypesSpacesFixer' => __DIR__ . '/../..' . '/src/Fixer/Whitespace/TypesSpacesFixer.php',
  4343. 'PhpCsFixer\\Fixer\\WhitespacesAwareFixerInterface' => __DIR__ . '/../..' . '/src/Fixer/WhitespacesAwareFixerInterface.php',
  4344. 'PhpCsFixer\\Hasher' => __DIR__ . '/../..' . '/src/Hasher.php',
  4345. 'PhpCsFixer\\Linter\\CachingLinter' => __DIR__ . '/../..' . '/src/Linter/CachingLinter.php',
  4346. 'PhpCsFixer\\Linter\\Linter' => __DIR__ . '/../..' . '/src/Linter/Linter.php',
  4347. 'PhpCsFixer\\Linter\\LinterInterface' => __DIR__ . '/../..' . '/src/Linter/LinterInterface.php',
  4348. 'PhpCsFixer\\Linter\\LintingException' => __DIR__ . '/../..' . '/src/Linter/LintingException.php',
  4349. 'PhpCsFixer\\Linter\\LintingResultInterface' => __DIR__ . '/../..' . '/src/Linter/LintingResultInterface.php',
  4350. 'PhpCsFixer\\Linter\\ProcessLinter' => __DIR__ . '/../..' . '/src/Linter/ProcessLinter.php',
  4351. 'PhpCsFixer\\Linter\\ProcessLinterProcessBuilder' => __DIR__ . '/../..' . '/src/Linter/ProcessLinterProcessBuilder.php',
  4352. 'PhpCsFixer\\Linter\\ProcessLintingResult' => __DIR__ . '/../..' . '/src/Linter/ProcessLintingResult.php',
  4353. 'PhpCsFixer\\Linter\\TokenizerLinter' => __DIR__ . '/../..' . '/src/Linter/TokenizerLinter.php',
  4354. 'PhpCsFixer\\Linter\\TokenizerLintingResult' => __DIR__ . '/../..' . '/src/Linter/TokenizerLintingResult.php',
  4355. 'PhpCsFixer\\Linter\\UnavailableLinterException' => __DIR__ . '/../..' . '/src/Linter/UnavailableLinterException.php',
  4356. 'PhpCsFixer\\ParallelAwareConfigInterface' => __DIR__ . '/../..' . '/src/ParallelAwareConfigInterface.php',
  4357. 'PhpCsFixer\\PharChecker' => __DIR__ . '/../..' . '/src/PharChecker.php',
  4358. 'PhpCsFixer\\PharCheckerInterface' => __DIR__ . '/../..' . '/src/PharCheckerInterface.php',
  4359. 'PhpCsFixer\\Preg' => __DIR__ . '/../..' . '/src/Preg.php',
  4360. 'PhpCsFixer\\PregException' => __DIR__ . '/../..' . '/src/PregException.php',
  4361. 'PhpCsFixer\\RuleSet\\AbstractMigrationSetDescription' => __DIR__ . '/../..' . '/src/RuleSet/AbstractMigrationSetDescription.php',
  4362. 'PhpCsFixer\\RuleSet\\AbstractRuleSetDescription' => __DIR__ . '/../..' . '/src/RuleSet/AbstractRuleSetDescription.php',
  4363. 'PhpCsFixer\\RuleSet\\DeprecatedRuleSetDescriptionInterface' => __DIR__ . '/../..' . '/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php',
  4364. 'PhpCsFixer\\RuleSet\\RuleSet' => __DIR__ . '/../..' . '/src/RuleSet/RuleSet.php',
  4365. 'PhpCsFixer\\RuleSet\\RuleSetDescriptionInterface' => __DIR__ . '/../..' . '/src/RuleSet/RuleSetDescriptionInterface.php',
  4366. 'PhpCsFixer\\RuleSet\\RuleSetInterface' => __DIR__ . '/../..' . '/src/RuleSet/RuleSetInterface.php',
  4367. 'PhpCsFixer\\RuleSet\\RuleSets' => __DIR__ . '/../..' . '/src/RuleSet/RuleSets.php',
  4368. 'PhpCsFixer\\RuleSet\\Sets\\DoctrineAnnotationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/DoctrineAnnotationSet.php',
  4369. 'PhpCsFixer\\RuleSet\\Sets\\PERCS1x0RiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCS1x0RiskySet.php',
  4370. 'PhpCsFixer\\RuleSet\\Sets\\PERCS1x0Set' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCS1x0Set.php',
  4371. 'PhpCsFixer\\RuleSet\\Sets\\PERCS2x0RiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCS2x0RiskySet.php',
  4372. 'PhpCsFixer\\RuleSet\\Sets\\PERCS2x0Set' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCS2x0Set.php',
  4373. 'PhpCsFixer\\RuleSet\\Sets\\PERCSRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCSRiskySet.php',
  4374. 'PhpCsFixer\\RuleSet\\Sets\\PERCSSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERCSSet.php',
  4375. 'PhpCsFixer\\RuleSet\\Sets\\PERRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERRiskySet.php',
  4376. 'PhpCsFixer\\RuleSet\\Sets\\PERSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PERSet.php',
  4377. 'PhpCsFixer\\RuleSet\\Sets\\PHP54MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP54MigrationSet.php',
  4378. 'PhpCsFixer\\RuleSet\\Sets\\PHP56MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP56MigrationRiskySet.php',
  4379. 'PhpCsFixer\\RuleSet\\Sets\\PHP70MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP70MigrationRiskySet.php',
  4380. 'PhpCsFixer\\RuleSet\\Sets\\PHP70MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP70MigrationSet.php',
  4381. 'PhpCsFixer\\RuleSet\\Sets\\PHP71MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP71MigrationRiskySet.php',
  4382. 'PhpCsFixer\\RuleSet\\Sets\\PHP71MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP71MigrationSet.php',
  4383. 'PhpCsFixer\\RuleSet\\Sets\\PHP73MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP73MigrationSet.php',
  4384. 'PhpCsFixer\\RuleSet\\Sets\\PHP74MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP74MigrationRiskySet.php',
  4385. 'PhpCsFixer\\RuleSet\\Sets\\PHP74MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP74MigrationSet.php',
  4386. 'PhpCsFixer\\RuleSet\\Sets\\PHP80MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP80MigrationRiskySet.php',
  4387. 'PhpCsFixer\\RuleSet\\Sets\\PHP80MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP80MigrationSet.php',
  4388. 'PhpCsFixer\\RuleSet\\Sets\\PHP81MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP81MigrationSet.php',
  4389. 'PhpCsFixer\\RuleSet\\Sets\\PHP82MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP82MigrationRiskySet.php',
  4390. 'PhpCsFixer\\RuleSet\\Sets\\PHP82MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP82MigrationSet.php',
  4391. 'PhpCsFixer\\RuleSet\\Sets\\PHP83MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP83MigrationSet.php',
  4392. 'PhpCsFixer\\RuleSet\\Sets\\PHP84MigrationSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHP84MigrationSet.php',
  4393. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit100MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit100MigrationRiskySet.php',
  4394. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit30MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit30MigrationRiskySet.php',
  4395. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit32MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit32MigrationRiskySet.php',
  4396. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit35MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit35MigrationRiskySet.php',
  4397. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit43MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit43MigrationRiskySet.php',
  4398. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit48MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit48MigrationRiskySet.php',
  4399. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit50MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit50MigrationRiskySet.php',
  4400. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit52MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit52MigrationRiskySet.php',
  4401. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit54MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit54MigrationRiskySet.php',
  4402. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit55MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit55MigrationRiskySet.php',
  4403. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit56MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit56MigrationRiskySet.php',
  4404. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit57MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit57MigrationRiskySet.php',
  4405. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit60MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit60MigrationRiskySet.php',
  4406. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit75MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit75MigrationRiskySet.php',
  4407. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit84MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit84MigrationRiskySet.php',
  4408. 'PhpCsFixer\\RuleSet\\Sets\\PHPUnit91MigrationRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PHPUnit91MigrationRiskySet.php',
  4409. 'PhpCsFixer\\RuleSet\\Sets\\PSR12RiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PSR12RiskySet.php',
  4410. 'PhpCsFixer\\RuleSet\\Sets\\PSR12Set' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PSR12Set.php',
  4411. 'PhpCsFixer\\RuleSet\\Sets\\PSR1Set' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PSR1Set.php',
  4412. 'PhpCsFixer\\RuleSet\\Sets\\PSR2Set' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PSR2Set.php',
  4413. 'PhpCsFixer\\RuleSet\\Sets\\PhpCsFixerRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PhpCsFixerRiskySet.php',
  4414. 'PhpCsFixer\\RuleSet\\Sets\\PhpCsFixerSet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/PhpCsFixerSet.php',
  4415. 'PhpCsFixer\\RuleSet\\Sets\\SymfonyRiskySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/SymfonyRiskySet.php',
  4416. 'PhpCsFixer\\RuleSet\\Sets\\SymfonySet' => __DIR__ . '/../..' . '/src/RuleSet/Sets/SymfonySet.php',
  4417. 'PhpCsFixer\\Runner\\Event\\AnalysisStarted' => __DIR__ . '/../..' . '/src/Runner/Event/AnalysisStarted.php',
  4418. 'PhpCsFixer\\Runner\\Event\\FileProcessed' => __DIR__ . '/../..' . '/src/Runner/Event/FileProcessed.php',
  4419. 'PhpCsFixer\\Runner\\FileCachingLintingFileIterator' => __DIR__ . '/../..' . '/src/Runner/FileCachingLintingFileIterator.php',
  4420. 'PhpCsFixer\\Runner\\FileFilterIterator' => __DIR__ . '/../..' . '/src/Runner/FileFilterIterator.php',
  4421. 'PhpCsFixer\\Runner\\LintingFileIterator' => __DIR__ . '/../..' . '/src/Runner/LintingFileIterator.php',
  4422. 'PhpCsFixer\\Runner\\LintingResultAwareFileIteratorInterface' => __DIR__ . '/../..' . '/src/Runner/LintingResultAwareFileIteratorInterface.php',
  4423. 'PhpCsFixer\\Runner\\Parallel\\ParallelAction' => __DIR__ . '/../..' . '/src/Runner/Parallel/ParallelAction.php',
  4424. 'PhpCsFixer\\Runner\\Parallel\\ParallelConfig' => __DIR__ . '/../..' . '/src/Runner/Parallel/ParallelConfig.php',
  4425. 'PhpCsFixer\\Runner\\Parallel\\ParallelConfigFactory' => __DIR__ . '/../..' . '/src/Runner/Parallel/ParallelConfigFactory.php',
  4426. 'PhpCsFixer\\Runner\\Parallel\\ParallelisationException' => __DIR__ . '/../..' . '/src/Runner/Parallel/ParallelisationException.php',
  4427. 'PhpCsFixer\\Runner\\Parallel\\Process' => __DIR__ . '/../..' . '/src/Runner/Parallel/Process.php',
  4428. 'PhpCsFixer\\Runner\\Parallel\\ProcessFactory' => __DIR__ . '/../..' . '/src/Runner/Parallel/ProcessFactory.php',
  4429. 'PhpCsFixer\\Runner\\Parallel\\ProcessIdentifier' => __DIR__ . '/../..' . '/src/Runner/Parallel/ProcessIdentifier.php',
  4430. 'PhpCsFixer\\Runner\\Parallel\\ProcessPool' => __DIR__ . '/../..' . '/src/Runner/Parallel/ProcessPool.php',
  4431. 'PhpCsFixer\\Runner\\Parallel\\WorkerException' => __DIR__ . '/../..' . '/src/Runner/Parallel/WorkerException.php',
  4432. 'PhpCsFixer\\Runner\\Runner' => __DIR__ . '/../..' . '/src/Runner/Runner.php',
  4433. 'PhpCsFixer\\Runner\\RunnerConfig' => __DIR__ . '/../..' . '/src/Runner/RunnerConfig.php',
  4434. 'PhpCsFixer\\StdinFileInfo' => __DIR__ . '/../..' . '/src/StdinFileInfo.php',
  4435. 'PhpCsFixer\\Tokenizer\\AbstractTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/AbstractTransformer.php',
  4436. 'PhpCsFixer\\Tokenizer\\AbstractTypeTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/AbstractTypeTransformer.php',
  4437. 'PhpCsFixer\\Tokenizer\\Analyzer\\AlternativeSyntaxAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/AlternativeSyntaxAnalyzer.php',
  4438. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\AbstractControlCaseStructuresAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/AbstractControlCaseStructuresAnalysis.php',
  4439. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\ArgumentAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/ArgumentAnalysis.php',
  4440. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\AttributeAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/AttributeAnalysis.php',
  4441. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\CaseAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/CaseAnalysis.php',
  4442. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\DataProviderAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/DataProviderAnalysis.php',
  4443. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\DefaultAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/DefaultAnalysis.php',
  4444. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\EnumAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/EnumAnalysis.php',
  4445. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\MatchAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/MatchAnalysis.php',
  4446. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\NamespaceAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/NamespaceAnalysis.php',
  4447. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\NamespaceUseAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/NamespaceUseAnalysis.php',
  4448. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\StartEndTokenAwareAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/StartEndTokenAwareAnalysis.php',
  4449. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\SwitchAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/SwitchAnalysis.php',
  4450. 'PhpCsFixer\\Tokenizer\\Analyzer\\Analysis\\TypeAnalysis' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php',
  4451. 'PhpCsFixer\\Tokenizer\\Analyzer\\ArgumentsAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/ArgumentsAnalyzer.php',
  4452. 'PhpCsFixer\\Tokenizer\\Analyzer\\AttributeAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/AttributeAnalyzer.php',
  4453. 'PhpCsFixer\\Tokenizer\\Analyzer\\BlocksAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/BlocksAnalyzer.php',
  4454. 'PhpCsFixer\\Tokenizer\\Analyzer\\ClassyAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/ClassyAnalyzer.php',
  4455. 'PhpCsFixer\\Tokenizer\\Analyzer\\CommentsAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/CommentsAnalyzer.php',
  4456. 'PhpCsFixer\\Tokenizer\\Analyzer\\ControlCaseStructuresAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/ControlCaseStructuresAnalyzer.php',
  4457. 'PhpCsFixer\\Tokenizer\\Analyzer\\DataProviderAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/DataProviderAnalyzer.php',
  4458. 'PhpCsFixer\\Tokenizer\\Analyzer\\FullyQualifiedNameAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/FullyQualifiedNameAnalyzer.php',
  4459. 'PhpCsFixer\\Tokenizer\\Analyzer\\FunctionsAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/FunctionsAnalyzer.php',
  4460. 'PhpCsFixer\\Tokenizer\\Analyzer\\GotoLabelAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/GotoLabelAnalyzer.php',
  4461. 'PhpCsFixer\\Tokenizer\\Analyzer\\NamespaceUsesAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/NamespaceUsesAnalyzer.php',
  4462. 'PhpCsFixer\\Tokenizer\\Analyzer\\NamespacesAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/NamespacesAnalyzer.php',
  4463. 'PhpCsFixer\\Tokenizer\\Analyzer\\PhpUnitTestCaseAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/PhpUnitTestCaseAnalyzer.php',
  4464. 'PhpCsFixer\\Tokenizer\\Analyzer\\RangeAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/RangeAnalyzer.php',
  4465. 'PhpCsFixer\\Tokenizer\\Analyzer\\ReferenceAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/ReferenceAnalyzer.php',
  4466. 'PhpCsFixer\\Tokenizer\\Analyzer\\SwitchAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/SwitchAnalyzer.php',
  4467. 'PhpCsFixer\\Tokenizer\\Analyzer\\WhitespacesAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/Analyzer/WhitespacesAnalyzer.php',
  4468. 'PhpCsFixer\\Tokenizer\\CT' => __DIR__ . '/../..' . '/src/Tokenizer/CT.php',
  4469. 'PhpCsFixer\\Tokenizer\\FCT' => __DIR__ . '/../..' . '/src/Tokenizer/FCT.php',
  4470. 'PhpCsFixer\\Tokenizer\\Processor\\ImportProcessor' => __DIR__ . '/../..' . '/src/Tokenizer/Processor/ImportProcessor.php',
  4471. 'PhpCsFixer\\Tokenizer\\Token' => __DIR__ . '/../..' . '/src/Tokenizer/Token.php',
  4472. 'PhpCsFixer\\Tokenizer\\Tokens' => __DIR__ . '/../..' . '/src/Tokenizer/Tokens.php',
  4473. 'PhpCsFixer\\Tokenizer\\TokensAnalyzer' => __DIR__ . '/../..' . '/src/Tokenizer/TokensAnalyzer.php',
  4474. 'PhpCsFixer\\Tokenizer\\TransformerInterface' => __DIR__ . '/../..' . '/src/Tokenizer/TransformerInterface.php',
  4475. 'PhpCsFixer\\Tokenizer\\Transformer\\ArrayTypehintTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/ArrayTypehintTransformer.php',
  4476. 'PhpCsFixer\\Tokenizer\\Transformer\\AttributeTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/AttributeTransformer.php',
  4477. 'PhpCsFixer\\Tokenizer\\Transformer\\BraceClassInstantiationTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/BraceClassInstantiationTransformer.php',
  4478. 'PhpCsFixer\\Tokenizer\\Transformer\\BraceTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/BraceTransformer.php',
  4479. 'PhpCsFixer\\Tokenizer\\Transformer\\ClassConstantTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/ClassConstantTransformer.php',
  4480. 'PhpCsFixer\\Tokenizer\\Transformer\\ConstructorPromotionTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/ConstructorPromotionTransformer.php',
  4481. 'PhpCsFixer\\Tokenizer\\Transformer\\DisjunctiveNormalFormTypeParenthesisTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/DisjunctiveNormalFormTypeParenthesisTransformer.php',
  4482. 'PhpCsFixer\\Tokenizer\\Transformer\\FirstClassCallableTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/FirstClassCallableTransformer.php',
  4483. 'PhpCsFixer\\Tokenizer\\Transformer\\ImportTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/ImportTransformer.php',
  4484. 'PhpCsFixer\\Tokenizer\\Transformer\\NameQualifiedTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/NameQualifiedTransformer.php',
  4485. 'PhpCsFixer\\Tokenizer\\Transformer\\NamedArgumentTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/NamedArgumentTransformer.php',
  4486. 'PhpCsFixer\\Tokenizer\\Transformer\\NamespaceOperatorTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/NamespaceOperatorTransformer.php',
  4487. 'PhpCsFixer\\Tokenizer\\Transformer\\NullableTypeTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/NullableTypeTransformer.php',
  4488. 'PhpCsFixer\\Tokenizer\\Transformer\\ReturnRefTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/ReturnRefTransformer.php',
  4489. 'PhpCsFixer\\Tokenizer\\Transformer\\SquareBraceTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/SquareBraceTransformer.php',
  4490. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeAlternationTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/TypeAlternationTransformer.php',
  4491. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeColonTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/TypeColonTransformer.php',
  4492. 'PhpCsFixer\\Tokenizer\\Transformer\\TypeIntersectionTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/TypeIntersectionTransformer.php',
  4493. 'PhpCsFixer\\Tokenizer\\Transformer\\UseTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/UseTransformer.php',
  4494. 'PhpCsFixer\\Tokenizer\\Transformer\\WhitespacyCommentTransformer' => __DIR__ . '/../..' . '/src/Tokenizer/Transformer/WhitespacyCommentTransformer.php',
  4495. 'PhpCsFixer\\Tokenizer\\Transformers' => __DIR__ . '/../..' . '/src/Tokenizer/Transformers.php',
  4496. 'PhpCsFixer\\ToolInfo' => __DIR__ . '/../..' . '/src/ToolInfo.php',
  4497. 'PhpCsFixer\\ToolInfoInterface' => __DIR__ . '/../..' . '/src/ToolInfoInterface.php',
  4498. 'PhpCsFixer\\UnsupportedPhpVersionAllowedConfigInterface' => __DIR__ . '/../..' . '/src/UnsupportedPhpVersionAllowedConfigInterface.php',
  4499. 'PhpCsFixer\\Utils' => __DIR__ . '/../..' . '/src/Utils.php',
  4500. 'PhpCsFixer\\WhitespacesFixerConfig' => __DIR__ . '/../..' . '/src/WhitespacesFixerConfig.php',
  4501. 'PhpCsFixer\\WordMatcher' => __DIR__ . '/../..' . '/src/WordMatcher.php',
  4502. 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
  4503. 'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
  4504. 'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
  4505. 'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
  4506. 'Psr\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/EventDispatcherInterface.php',
  4507. 'Psr\\EventDispatcher\\ListenerProviderInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/ListenerProviderInterface.php',
  4508. 'Psr\\EventDispatcher\\StoppableEventInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/StoppableEventInterface.php',
  4509. 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php',
  4510. 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php',
  4511. 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php',
  4512. 'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php',
  4513. 'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php',
  4514. 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php',
  4515. 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php',
  4516. 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php',
  4517. 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php',
  4518. 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
  4519. 'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php',
  4520. 'React\\Cache\\ArrayCache' => __DIR__ . '/..' . '/react/cache/src/ArrayCache.php',
  4521. 'React\\Cache\\CacheInterface' => __DIR__ . '/..' . '/react/cache/src/CacheInterface.php',
  4522. 'React\\ChildProcess\\Process' => __DIR__ . '/..' . '/react/child-process/src/Process.php',
  4523. 'React\\Dns\\BadServerException' => __DIR__ . '/..' . '/react/dns/src/BadServerException.php',
  4524. 'React\\Dns\\Config\\Config' => __DIR__ . '/..' . '/react/dns/src/Config/Config.php',
  4525. 'React\\Dns\\Config\\HostsFile' => __DIR__ . '/..' . '/react/dns/src/Config/HostsFile.php',
  4526. 'React\\Dns\\Model\\Message' => __DIR__ . '/..' . '/react/dns/src/Model/Message.php',
  4527. 'React\\Dns\\Model\\Record' => __DIR__ . '/..' . '/react/dns/src/Model/Record.php',
  4528. 'React\\Dns\\Protocol\\BinaryDumper' => __DIR__ . '/..' . '/react/dns/src/Protocol/BinaryDumper.php',
  4529. 'React\\Dns\\Protocol\\Parser' => __DIR__ . '/..' . '/react/dns/src/Protocol/Parser.php',
  4530. 'React\\Dns\\Query\\CachingExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/CachingExecutor.php',
  4531. 'React\\Dns\\Query\\CancellationException' => __DIR__ . '/..' . '/react/dns/src/Query/CancellationException.php',
  4532. 'React\\Dns\\Query\\CoopExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/CoopExecutor.php',
  4533. 'React\\Dns\\Query\\ExecutorInterface' => __DIR__ . '/..' . '/react/dns/src/Query/ExecutorInterface.php',
  4534. 'React\\Dns\\Query\\FallbackExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/FallbackExecutor.php',
  4535. 'React\\Dns\\Query\\HostsFileExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/HostsFileExecutor.php',
  4536. 'React\\Dns\\Query\\Query' => __DIR__ . '/..' . '/react/dns/src/Query/Query.php',
  4537. 'React\\Dns\\Query\\RetryExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/RetryExecutor.php',
  4538. 'React\\Dns\\Query\\SelectiveTransportExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/SelectiveTransportExecutor.php',
  4539. 'React\\Dns\\Query\\TcpTransportExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/TcpTransportExecutor.php',
  4540. 'React\\Dns\\Query\\TimeoutException' => __DIR__ . '/..' . '/react/dns/src/Query/TimeoutException.php',
  4541. 'React\\Dns\\Query\\TimeoutExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/TimeoutExecutor.php',
  4542. 'React\\Dns\\Query\\UdpTransportExecutor' => __DIR__ . '/..' . '/react/dns/src/Query/UdpTransportExecutor.php',
  4543. 'React\\Dns\\RecordNotFoundException' => __DIR__ . '/..' . '/react/dns/src/RecordNotFoundException.php',
  4544. 'React\\Dns\\Resolver\\Factory' => __DIR__ . '/..' . '/react/dns/src/Resolver/Factory.php',
  4545. 'React\\Dns\\Resolver\\Resolver' => __DIR__ . '/..' . '/react/dns/src/Resolver/Resolver.php',
  4546. 'React\\Dns\\Resolver\\ResolverInterface' => __DIR__ . '/..' . '/react/dns/src/Resolver/ResolverInterface.php',
  4547. 'React\\EventLoop\\ExtEvLoop' => __DIR__ . '/..' . '/react/event-loop/src/ExtEvLoop.php',
  4548. 'React\\EventLoop\\ExtEventLoop' => __DIR__ . '/..' . '/react/event-loop/src/ExtEventLoop.php',
  4549. 'React\\EventLoop\\ExtLibevLoop' => __DIR__ . '/..' . '/react/event-loop/src/ExtLibevLoop.php',
  4550. 'React\\EventLoop\\ExtLibeventLoop' => __DIR__ . '/..' . '/react/event-loop/src/ExtLibeventLoop.php',
  4551. 'React\\EventLoop\\ExtUvLoop' => __DIR__ . '/..' . '/react/event-loop/src/ExtUvLoop.php',
  4552. 'React\\EventLoop\\Factory' => __DIR__ . '/..' . '/react/event-loop/src/Factory.php',
  4553. 'React\\EventLoop\\Loop' => __DIR__ . '/..' . '/react/event-loop/src/Loop.php',
  4554. 'React\\EventLoop\\LoopInterface' => __DIR__ . '/..' . '/react/event-loop/src/LoopInterface.php',
  4555. 'React\\EventLoop\\SignalsHandler' => __DIR__ . '/..' . '/react/event-loop/src/SignalsHandler.php',
  4556. 'React\\EventLoop\\StreamSelectLoop' => __DIR__ . '/..' . '/react/event-loop/src/StreamSelectLoop.php',
  4557. 'React\\EventLoop\\Tick\\FutureTickQueue' => __DIR__ . '/..' . '/react/event-loop/src/Tick/FutureTickQueue.php',
  4558. 'React\\EventLoop\\TimerInterface' => __DIR__ . '/..' . '/react/event-loop/src/TimerInterface.php',
  4559. 'React\\EventLoop\\Timer\\Timer' => __DIR__ . '/..' . '/react/event-loop/src/Timer/Timer.php',
  4560. 'React\\EventLoop\\Timer\\Timers' => __DIR__ . '/..' . '/react/event-loop/src/Timer/Timers.php',
  4561. 'React\\Promise\\Deferred' => __DIR__ . '/..' . '/react/promise/src/Deferred.php',
  4562. 'React\\Promise\\Exception\\CompositeException' => __DIR__ . '/..' . '/react/promise/src/Exception/CompositeException.php',
  4563. 'React\\Promise\\Exception\\LengthException' => __DIR__ . '/..' . '/react/promise/src/Exception/LengthException.php',
  4564. 'React\\Promise\\Internal\\CancellationQueue' => __DIR__ . '/..' . '/react/promise/src/Internal/CancellationQueue.php',
  4565. 'React\\Promise\\Internal\\FulfilledPromise' => __DIR__ . '/..' . '/react/promise/src/Internal/FulfilledPromise.php',
  4566. 'React\\Promise\\Internal\\RejectedPromise' => __DIR__ . '/..' . '/react/promise/src/Internal/RejectedPromise.php',
  4567. 'React\\Promise\\Promise' => __DIR__ . '/..' . '/react/promise/src/Promise.php',
  4568. 'React\\Promise\\PromiseInterface' => __DIR__ . '/..' . '/react/promise/src/PromiseInterface.php',
  4569. 'React\\Socket\\Connection' => __DIR__ . '/..' . '/react/socket/src/Connection.php',
  4570. 'React\\Socket\\ConnectionInterface' => __DIR__ . '/..' . '/react/socket/src/ConnectionInterface.php',
  4571. 'React\\Socket\\Connector' => __DIR__ . '/..' . '/react/socket/src/Connector.php',
  4572. 'React\\Socket\\ConnectorInterface' => __DIR__ . '/..' . '/react/socket/src/ConnectorInterface.php',
  4573. 'React\\Socket\\DnsConnector' => __DIR__ . '/..' . '/react/socket/src/DnsConnector.php',
  4574. 'React\\Socket\\FdServer' => __DIR__ . '/..' . '/react/socket/src/FdServer.php',
  4575. 'React\\Socket\\FixedUriConnector' => __DIR__ . '/..' . '/react/socket/src/FixedUriConnector.php',
  4576. 'React\\Socket\\HappyEyeBallsConnectionBuilder' => __DIR__ . '/..' . '/react/socket/src/HappyEyeBallsConnectionBuilder.php',
  4577. 'React\\Socket\\HappyEyeBallsConnector' => __DIR__ . '/..' . '/react/socket/src/HappyEyeBallsConnector.php',
  4578. 'React\\Socket\\LimitingServer' => __DIR__ . '/..' . '/react/socket/src/LimitingServer.php',
  4579. 'React\\Socket\\SecureConnector' => __DIR__ . '/..' . '/react/socket/src/SecureConnector.php',
  4580. 'React\\Socket\\SecureServer' => __DIR__ . '/..' . '/react/socket/src/SecureServer.php',
  4581. 'React\\Socket\\Server' => __DIR__ . '/..' . '/react/socket/src/Server.php',
  4582. 'React\\Socket\\ServerInterface' => __DIR__ . '/..' . '/react/socket/src/ServerInterface.php',
  4583. 'React\\Socket\\SocketServer' => __DIR__ . '/..' . '/react/socket/src/SocketServer.php',
  4584. 'React\\Socket\\StreamEncryption' => __DIR__ . '/..' . '/react/socket/src/StreamEncryption.php',
  4585. 'React\\Socket\\TcpConnector' => __DIR__ . '/..' . '/react/socket/src/TcpConnector.php',
  4586. 'React\\Socket\\TcpServer' => __DIR__ . '/..' . '/react/socket/src/TcpServer.php',
  4587. 'React\\Socket\\TimeoutConnector' => __DIR__ . '/..' . '/react/socket/src/TimeoutConnector.php',
  4588. 'React\\Socket\\UnixConnector' => __DIR__ . '/..' . '/react/socket/src/UnixConnector.php',
  4589. 'React\\Socket\\UnixServer' => __DIR__ . '/..' . '/react/socket/src/UnixServer.php',
  4590. 'React\\Stream\\CompositeStream' => __DIR__ . '/..' . '/react/stream/src/CompositeStream.php',
  4591. 'React\\Stream\\DuplexResourceStream' => __DIR__ . '/..' . '/react/stream/src/DuplexResourceStream.php',
  4592. 'React\\Stream\\DuplexStreamInterface' => __DIR__ . '/..' . '/react/stream/src/DuplexStreamInterface.php',
  4593. 'React\\Stream\\ReadableResourceStream' => __DIR__ . '/..' . '/react/stream/src/ReadableResourceStream.php',
  4594. 'React\\Stream\\ReadableStreamInterface' => __DIR__ . '/..' . '/react/stream/src/ReadableStreamInterface.php',
  4595. 'React\\Stream\\ThroughStream' => __DIR__ . '/..' . '/react/stream/src/ThroughStream.php',
  4596. 'React\\Stream\\Util' => __DIR__ . '/..' . '/react/stream/src/Util.php',
  4597. 'React\\Stream\\WritableResourceStream' => __DIR__ . '/..' . '/react/stream/src/WritableResourceStream.php',
  4598. 'React\\Stream\\WritableStreamInterface' => __DIR__ . '/..' . '/react/stream/src/WritableStreamInterface.php',
  4599. 'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
  4600. 'SebastianBergmann\\Diff\\Chunk' => __DIR__ . '/..' . '/sebastian/diff/src/Chunk.php',
  4601. 'SebastianBergmann\\Diff\\ConfigurationException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/ConfigurationException.php',
  4602. 'SebastianBergmann\\Diff\\Diff' => __DIR__ . '/..' . '/sebastian/diff/src/Diff.php',
  4603. 'SebastianBergmann\\Diff\\Differ' => __DIR__ . '/..' . '/sebastian/diff/src/Differ.php',
  4604. 'SebastianBergmann\\Diff\\Exception' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/Exception.php',
  4605. 'SebastianBergmann\\Diff\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/InvalidArgumentException.php',
  4606. 'SebastianBergmann\\Diff\\Line' => __DIR__ . '/..' . '/sebastian/diff/src/Line.php',
  4607. 'SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php',
  4608. 'SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php',
  4609. 'SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php',
  4610. 'SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php',
  4611. 'SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php',
  4612. 'SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php',
  4613. 'SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php',
  4614. 'SebastianBergmann\\Diff\\Parser' => __DIR__ . '/..' . '/sebastian/diff/src/Parser.php',
  4615. 'SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php',
  4616. 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
  4617. 'Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php',
  4618. 'Symfony\\Component\\Console\\Attribute\\AsCommand' => __DIR__ . '/..' . '/symfony/console/Attribute/AsCommand.php',
  4619. 'Symfony\\Component\\Console\\CI\\GithubActionReporter' => __DIR__ . '/..' . '/symfony/console/CI/GithubActionReporter.php',
  4620. 'Symfony\\Component\\Console\\Color' => __DIR__ . '/..' . '/symfony/console/Color.php',
  4621. 'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
  4622. 'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
  4623. 'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
  4624. 'Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php',
  4625. 'Symfony\\Component\\Console\\Command\\CompleteCommand' => __DIR__ . '/..' . '/symfony/console/Command/CompleteCommand.php',
  4626. 'Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => __DIR__ . '/..' . '/symfony/console/Command/DumpCompletionCommand.php',
  4627. 'Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php',
  4628. 'Symfony\\Component\\Console\\Command\\LazyCommand' => __DIR__ . '/..' . '/symfony/console/Command/LazyCommand.php',
  4629. 'Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php',
  4630. 'Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php',
  4631. 'Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => __DIR__ . '/..' . '/symfony/console/Command/SignalableCommandInterface.php',
  4632. 'Symfony\\Component\\Console\\Completion\\CompletionInput' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionInput.php',
  4633. 'Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionSuggestions.php',
  4634. 'Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/BashCompletionOutput.php',
  4635. 'Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => __DIR__ . '/..' . '/symfony/console/Completion/Output/CompletionOutputInterface.php',
  4636. 'Symfony\\Component\\Console\\Completion\\Suggestion' => __DIR__ . '/..' . '/symfony/console/Completion/Suggestion.php',
  4637. 'Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php',
  4638. 'Symfony\\Component\\Console\\Cursor' => __DIR__ . '/..' . '/symfony/console/Cursor.php',
  4639. 'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
  4640. 'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php',
  4641. 'Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php',
  4642. 'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php',
  4643. 'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php',
  4644. 'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php',
  4645. 'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php',
  4646. 'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php',
  4647. 'Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php',
  4648. 'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php',
  4649. 'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php',
  4650. 'Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php',
  4651. 'Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleSignalEvent.php',
  4652. 'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php',
  4653. 'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php',
  4654. 'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php',
  4655. 'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php',
  4656. 'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php',
  4657. 'Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php',
  4658. 'Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php',
  4659. 'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php',
  4660. 'Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php',
  4661. 'Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatter.php',
  4662. 'Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatterStyle.php',
  4663. 'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php',
  4664. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php',
  4665. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php',
  4666. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
  4667. 'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
  4668. 'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
  4669. 'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php',
  4670. 'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php',
  4671. 'Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php',
  4672. 'Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php',
  4673. 'Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php',
  4674. 'Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php',
  4675. 'Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php',
  4676. 'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php',
  4677. 'Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php',
  4678. 'Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php',
  4679. 'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php',
  4680. 'Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php',
  4681. 'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php',
  4682. 'Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php',
  4683. 'Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php',
  4684. 'Symfony\\Component\\Console\\Helper\\TableCellStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableCellStyle.php',
  4685. 'Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php',
  4686. 'Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php',
  4687. 'Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php',
  4688. 'Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php',
  4689. 'Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php',
  4690. 'Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php',
  4691. 'Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php',
  4692. 'Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php',
  4693. 'Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php',
  4694. 'Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php',
  4695. 'Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php',
  4696. 'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php',
  4697. 'Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php',
  4698. 'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php',
  4699. 'Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php',
  4700. 'Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php',
  4701. 'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php',
  4702. 'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php',
  4703. 'Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php',
  4704. 'Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php',
  4705. 'Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php',
  4706. 'Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php',
  4707. 'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php',
  4708. 'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php',
  4709. 'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php',
  4710. 'Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php',
  4711. 'Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalRegistry.php',
  4712. 'Symfony\\Component\\Console\\SingleCommandApplication' => __DIR__ . '/..' . '/symfony/console/SingleCommandApplication.php',
  4713. 'Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php',
  4714. 'Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php',
  4715. 'Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php',
  4716. 'Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php',
  4717. 'Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php',
  4718. 'Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandCompletionTester.php',
  4719. 'Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php',
  4720. 'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => __DIR__ . '/..' . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php',
  4721. 'Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php',
  4722. 'Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener' => __DIR__ . '/..' . '/symfony/event-dispatcher/Attribute/AsEventListener.php',
  4723. 'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
  4724. 'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/WrappedListener.php',
  4725. 'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
  4726. 'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
  4727. 'Symfony\\Component\\EventDispatcher\\EventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcher.php',
  4728. 'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcherInterface.php',
  4729. 'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventSubscriberInterface.php',
  4730. 'Symfony\\Component\\EventDispatcher\\GenericEvent' => __DIR__ . '/..' . '/symfony/event-dispatcher/GenericEvent.php',
  4731. 'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
  4732. 'Symfony\\Component\\EventDispatcher\\LegacyEventDispatcherProxy' => __DIR__ . '/..' . '/symfony/event-dispatcher/LegacyEventDispatcherProxy.php',
  4733. 'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php',
  4734. 'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php',
  4735. 'Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php',
  4736. 'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOExceptionInterface.php',
  4737. 'Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/InvalidArgumentException.php',
  4738. 'Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/RuntimeException.php',
  4739. 'Symfony\\Component\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/symfony/filesystem/Filesystem.php',
  4740. 'Symfony\\Component\\Filesystem\\Path' => __DIR__ . '/..' . '/symfony/filesystem/Path.php',
  4741. 'Symfony\\Component\\Finder\\Comparator\\Comparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/Comparator.php',
  4742. 'Symfony\\Component\\Finder\\Comparator\\DateComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/DateComparator.php',
  4743. 'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/NumberComparator.php',
  4744. 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => __DIR__ . '/..' . '/symfony/finder/Exception/AccessDeniedException.php',
  4745. 'Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => __DIR__ . '/..' . '/symfony/finder/Exception/DirectoryNotFoundException.php',
  4746. 'Symfony\\Component\\Finder\\Finder' => __DIR__ . '/..' . '/symfony/finder/Finder.php',
  4747. 'Symfony\\Component\\Finder\\Gitignore' => __DIR__ . '/..' . '/symfony/finder/Gitignore.php',
  4748. 'Symfony\\Component\\Finder\\Glob' => __DIR__ . '/..' . '/symfony/finder/Glob.php',
  4749. 'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/CustomFilterIterator.php',
  4750. 'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
  4751. 'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
  4752. 'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
  4753. 'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
  4754. 'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
  4755. 'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilenameFilterIterator.php',
  4756. 'Symfony\\Component\\Finder\\Iterator\\LazyIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/LazyIterator.php',
  4757. 'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
  4758. 'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/PathFilterIterator.php',
  4759. 'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
  4760. 'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
  4761. 'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SortableIterator.php',
  4762. 'Symfony\\Component\\Finder\\Iterator\\VcsIgnoredFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/VcsIgnoredFilterIterator.php',
  4763. 'Symfony\\Component\\Finder\\SplFileInfo' => __DIR__ . '/..' . '/symfony/finder/SplFileInfo.php',
  4764. 'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => __DIR__ . '/..' . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
  4765. 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/AccessException.php',
  4766. 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/ExceptionInterface.php',
  4767. 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
  4768. 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
  4769. 'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/MissingOptionsException.php',
  4770. 'Symfony\\Component\\OptionsResolver\\Exception\\NoConfigurationException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/NoConfigurationException.php',
  4771. 'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
  4772. 'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
  4773. 'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
  4774. 'Symfony\\Component\\OptionsResolver\\OptionConfigurator' => __DIR__ . '/..' . '/symfony/options-resolver/OptionConfigurator.php',
  4775. 'Symfony\\Component\\OptionsResolver\\Options' => __DIR__ . '/..' . '/symfony/options-resolver/Options.php',
  4776. 'Symfony\\Component\\OptionsResolver\\OptionsResolver' => __DIR__ . '/..' . '/symfony/options-resolver/OptionsResolver.php',
  4777. 'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/process/Exception/ExceptionInterface.php',
  4778. 'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/process/Exception/InvalidArgumentException.php',
  4779. 'Symfony\\Component\\Process\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/process/Exception/LogicException.php',
  4780. 'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php',
  4781. 'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php',
  4782. 'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php',
  4783. 'Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php',
  4784. 'Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php',
  4785. 'Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php',
  4786. 'Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php',
  4787. 'Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php',
  4788. 'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php',
  4789. 'Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php',
  4790. 'Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php',
  4791. 'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/WindowsPipes.php',
  4792. 'Symfony\\Component\\Process\\Process' => __DIR__ . '/..' . '/symfony/process/Process.php',
  4793. 'Symfony\\Component\\Process\\ProcessUtils' => __DIR__ . '/..' . '/symfony/process/ProcessUtils.php',
  4794. 'Symfony\\Component\\Stopwatch\\Section' => __DIR__ . '/..' . '/symfony/stopwatch/Section.php',
  4795. 'Symfony\\Component\\Stopwatch\\Stopwatch' => __DIR__ . '/..' . '/symfony/stopwatch/Stopwatch.php',
  4796. 'Symfony\\Component\\Stopwatch\\StopwatchEvent' => __DIR__ . '/..' . '/symfony/stopwatch/StopwatchEvent.php',
  4797. 'Symfony\\Component\\Stopwatch\\StopwatchPeriod' => __DIR__ . '/..' . '/symfony/stopwatch/StopwatchPeriod.php',
  4798. 'Symfony\\Component\\String\\AbstractString' => __DIR__ . '/..' . '/symfony/string/AbstractString.php',
  4799. 'Symfony\\Component\\String\\AbstractUnicodeString' => __DIR__ . '/..' . '/symfony/string/AbstractUnicodeString.php',
  4800. 'Symfony\\Component\\String\\ByteString' => __DIR__ . '/..' . '/symfony/string/ByteString.php',
  4801. 'Symfony\\Component\\String\\CodePointString' => __DIR__ . '/..' . '/symfony/string/CodePointString.php',
  4802. 'Symfony\\Component\\String\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/string/Exception/ExceptionInterface.php',
  4803. 'Symfony\\Component\\String\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/string/Exception/InvalidArgumentException.php',
  4804. 'Symfony\\Component\\String\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/string/Exception/RuntimeException.php',
  4805. 'Symfony\\Component\\String\\Inflector\\EnglishInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/EnglishInflector.php',
  4806. 'Symfony\\Component\\String\\Inflector\\FrenchInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/FrenchInflector.php',
  4807. 'Symfony\\Component\\String\\Inflector\\InflectorInterface' => __DIR__ . '/..' . '/symfony/string/Inflector/InflectorInterface.php',
  4808. 'Symfony\\Component\\String\\LazyString' => __DIR__ . '/..' . '/symfony/string/LazyString.php',
  4809. 'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php',
  4810. 'Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php',
  4811. 'Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php',
  4812. 'Symfony\\Contracts\\EventDispatcher\\Event' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/Event.php',
  4813. 'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
  4814. 'Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php',
  4815. 'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php',
  4816. 'Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
  4817. 'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
  4818. 'Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
  4819. 'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
  4820. 'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
  4821. 'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => __DIR__ . '/..' . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
  4822. 'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTestCase' => __DIR__ . '/..' . '/symfony/service-contracts/Test/ServiceLocatorTestCase.php',
  4823. 'Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
  4824. 'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/Grapheme.php',
  4825. 'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php',
  4826. 'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
  4827. 'Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php',
  4828. 'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
  4829. 'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',
  4830. 'Symfony\\Polyfill\\Php81\\Php81' => __DIR__ . '/..' . '/symfony/polyfill-php81/Php81.php',
  4831. 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
  4832. 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
  4833. );
  4834. public static function getInitializer(ClassLoader $loader)
  4835. {
  4836. return \Closure::bind(function () use ($loader) {
  4837. $loader->prefixLengthsPsr4 = ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd::$prefixLengthsPsr4;
  4838. $loader->prefixDirsPsr4 = ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd::$prefixDirsPsr4;
  4839. $loader->classMap = ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd::$classMap;
  4840. }, null, ClassLoader::class);
  4841. }
  4842. }
  4843. <?php
  4844. class ComposerAutoloaderInit5516c75849ea283eeb16cdd35a9ac4cd
  4845. {
  4846. private static $loader;
  4847. public static function loadClassLoader($class)
  4848. {
  4849. if ('Composer\Autoload\ClassLoader' === $class) {
  4850. require __DIR__ . '/ClassLoader.php';
  4851. }
  4852. }
  4853. public static function getLoader()
  4854. {
  4855. if (null !== self::$loader) {
  4856. return self::$loader;
  4857. }
  4858. require __DIR__ . '/platform_check.php';
  4859. spl_autoload_register(array('ComposerAutoloaderInit5516c75849ea283eeb16cdd35a9ac4cd', 'loadClassLoader'), true, true);
  4860. self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
  4861. spl_autoload_unregister(array('ComposerAutoloaderInit5516c75849ea283eeb16cdd35a9ac4cd', 'loadClassLoader'));
  4862. require __DIR__ . '/autoload_static.php';
  4863. call_user_func(\Composer\Autoload\ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd::getInitializer($loader));
  4864. $loader->register(true);
  4865. $filesToLoad = \Composer\Autoload\ComposerStaticInit5516c75849ea283eeb16cdd35a9ac4cd::$files;
  4866. $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
  4867. if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  4868. $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
  4869. require $file;
  4870. }
  4871. }, null, null);
  4872. foreach ($filesToLoad as $fileIdentifier => $file) {
  4873. $requireFile($fileIdentifier, $file);
  4874. }
  4875. return $loader;
  4876. }
  4877. }
  4878. <?php
  4879. namespace Composer\Semver;
  4880. use Composer\Semver\Constraint\Constraint;
  4881. use Composer\Semver\Constraint\ConstraintInterface;
  4882. class CompilingMatcher
  4883. {
  4884. /**
  4885. @phpstan-var
  4886. */
  4887. private static $compiledCheckerCache = array();
  4888. /**
  4889. @phpstan-var
  4890. */
  4891. private static $resultCache = array();
  4892. private static $enabled;
  4893. /**
  4894. @phpstan-var
  4895. */
  4896. private static $transOpInt = array(
  4897. Constraint::OP_EQ => Constraint::STR_OP_EQ,
  4898. Constraint::OP_LT => Constraint::STR_OP_LT,
  4899. Constraint::OP_LE => Constraint::STR_OP_LE,
  4900. Constraint::OP_GT => Constraint::STR_OP_GT,
  4901. Constraint::OP_GE => Constraint::STR_OP_GE,
  4902. Constraint::OP_NE => Constraint::STR_OP_NE,
  4903. );
  4904. public static function clear()
  4905. {
  4906. self::$resultCache = array();
  4907. self::$compiledCheckerCache = array();
  4908. }
  4909. /**
  4910. @phpstan-param
  4911. */
  4912. public static function match(ConstraintInterface $constraint, $operator, $version)
  4913. {
  4914. $resultCacheKey = $operator.$constraint.';'.$version;
  4915. if (isset(self::$resultCache[$resultCacheKey])) {
  4916. return self::$resultCache[$resultCacheKey];
  4917. }
  4918. if (self::$enabled === null) {
  4919. self::$enabled = !\in_array('eval', explode(',', (string) ini_get('disable_functions')), true);
  4920. }
  4921. if (!self::$enabled) {
  4922. return self::$resultCache[$resultCacheKey] = $constraint->matches(new Constraint(self::$transOpInt[$operator], $version));
  4923. }
  4924. $cacheKey = $operator.$constraint;
  4925. if (!isset(self::$compiledCheckerCache[$cacheKey])) {
  4926. $code = $constraint->compile($operator);
  4927. self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return '.$code.';};');
  4928. } else {
  4929. $function = self::$compiledCheckerCache[$cacheKey];
  4930. }
  4931. return self::$resultCache[$resultCacheKey] = $function($version, strpos($version, 'dev-') === 0);
  4932. }
  4933. }
  4934. <?php
  4935. namespace Composer\Semver;
  4936. use Composer\Semver\Constraint\Constraint;
  4937. class Interval
  4938. {
  4939. private $start;
  4940. private $end;
  4941. public function __construct(Constraint $start, Constraint $end)
  4942. {
  4943. $this->start = $start;
  4944. $this->end = $end;
  4945. }
  4946. public function getStart()
  4947. {
  4948. return $this->start;
  4949. }
  4950. public function getEnd()
  4951. {
  4952. return $this->end;
  4953. }
  4954. public static function fromZero()
  4955. {
  4956. static $zero;
  4957. if (null === $zero) {
  4958. $zero = new Constraint('>=', '0.0.0.0-dev');
  4959. }
  4960. return $zero;
  4961. }
  4962. public static function untilPositiveInfinity()
  4963. {
  4964. static $positiveInfinity;
  4965. if (null === $positiveInfinity) {
  4966. $positiveInfinity = new Constraint('<', PHP_INT_MAX.'.0.0.0');
  4967. }
  4968. return $positiveInfinity;
  4969. }
  4970. public static function any()
  4971. {
  4972. return new self(self::fromZero(), self::untilPositiveInfinity());
  4973. }
  4974. public static function anyDev()
  4975. {
  4976. return array('names' => array(), 'exclude' => true);
  4977. }
  4978. public static function noDev()
  4979. {
  4980. return array('names' => array(), 'exclude' => false);
  4981. }
  4982. }
  4983. <?php
  4984. namespace Composer\Semver;
  4985. use Composer\Semver\Constraint\Constraint;
  4986. class Comparator
  4987. {
  4988. public static function greaterThan($version1, $version2)
  4989. {
  4990. return self::compare($version1, '>', $version2);
  4991. }
  4992. public static function greaterThanOrEqualTo($version1, $version2)
  4993. {
  4994. return self::compare($version1, '>=', $version2);
  4995. }
  4996. public static function lessThan($version1, $version2)
  4997. {
  4998. return self::compare($version1, '<', $version2);
  4999. }
  5000. public static function lessThanOrEqualTo($version1, $version2)
  5001. {
  5002. return self::compare($version1, '<=', $version2);
  5003. }
  5004. public static function equalTo($version1, $version2)
  5005. {
  5006. return self::compare($version1, '==', $version2);
  5007. }
  5008. public static function notEqualTo($version1, $version2)
  5009. {
  5010. return self::compare($version1, '!=', $version2);
  5011. }
  5012. /**
  5013. @phpstan-param
  5014. */
  5015. public static function compare($version1, $operator, $version2)
  5016. {
  5017. $constraint = new Constraint($operator, $version2);
  5018. return $constraint->matchSpecific(new Constraint('==', $version1), true);
  5019. }
  5020. }
  5021. <?php
  5022. namespace Composer\Semver;
  5023. use Composer\Semver\Constraint\Constraint;
  5024. use Composer\Semver\Constraint\ConstraintInterface;
  5025. use Composer\Semver\Constraint\MatchAllConstraint;
  5026. use Composer\Semver\Constraint\MatchNoneConstraint;
  5027. use Composer\Semver\Constraint\MultiConstraint;
  5028. class Intervals
  5029. {
  5030. /**
  5031. @phpstan-var
  5032. */
  5033. private static $intervalsCache = array();
  5034. /**
  5035. @phpstan-var
  5036. */
  5037. private static $opSortOrder = array(
  5038. '>=' => -3,
  5039. '<' => -2,
  5040. '>' => 2,
  5041. '<=' => 3,
  5042. );
  5043. public static function clear()
  5044. {
  5045. self::$intervalsCache = array();
  5046. }
  5047. public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint)
  5048. {
  5049. if ($constraint instanceof MatchAllConstraint) {
  5050. return true;
  5051. }
  5052. if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) {
  5053. return false;
  5054. }
  5055. $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), true));
  5056. $candidateIntervals = self::get($candidate);
  5057. if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) {
  5058. return false;
  5059. }
  5060. foreach ($intersectionIntervals['numeric'] as $index => $interval) {
  5061. if (!isset($candidateIntervals['numeric'][$index])) {
  5062. return false;
  5063. }
  5064. if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) {
  5065. return false;
  5066. }
  5067. if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) {
  5068. return false;
  5069. }
  5070. }
  5071. if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) {
  5072. return false;
  5073. }
  5074. if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) {
  5075. return false;
  5076. }
  5077. foreach ($intersectionIntervals['branches']['names'] as $index => $name) {
  5078. if ($name !== $candidateIntervals['branches']['names'][$index]) {
  5079. return false;
  5080. }
  5081. }
  5082. return true;
  5083. }
  5084. public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b)
  5085. {
  5086. if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) {
  5087. return true;
  5088. }
  5089. if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) {
  5090. return false;
  5091. }
  5092. $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), true), true);
  5093. return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0;
  5094. }
  5095. public static function compactConstraint(ConstraintInterface $constraint)
  5096. {
  5097. if (!$constraint instanceof MultiConstraint) {
  5098. return $constraint;
  5099. }
  5100. $intervals = self::generateIntervals($constraint);
  5101. $constraints = array();
  5102. $hasNumericMatchAll = false;
  5103. if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) {
  5104. $constraints[] = $intervals['numeric'][0]->getStart();
  5105. $hasNumericMatchAll = true;
  5106. } else {
  5107. $unEqualConstraints = array();
  5108. for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) {
  5109. $interval = $intervals['numeric'][$i];
  5110. if ($interval->getEnd()->getOperator() === '<' && $i+1 < $count) {
  5111. $nextInterval = $intervals['numeric'][$i+1];
  5112. if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') {
  5113. if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) {
  5114. $unEqualConstraints[] = $interval->getStart();
  5115. }
  5116. $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion());
  5117. continue;
  5118. }
  5119. }
  5120. if (\count($unEqualConstraints) > 0) {
  5121. if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) {
  5122. $unEqualConstraints[] = $interval->getEnd();
  5123. }
  5124. if (\count($unEqualConstraints) > 1) {
  5125. $constraints[] = new MultiConstraint($unEqualConstraints, true);
  5126. } else {
  5127. $constraints[] = $unEqualConstraints[0];
  5128. }
  5129. $unEqualConstraints = array();
  5130. continue;
  5131. }
  5132. if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') {
  5133. $constraints[] = new Constraint('==', $interval->getStart()->getVersion());
  5134. continue;
  5135. }
  5136. if ((string) $interval->getStart() === (string) Interval::fromZero()) {
  5137. $constraints[] = $interval->getEnd();
  5138. } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) {
  5139. $constraints[] = $interval->getStart();
  5140. } else {
  5141. $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), true);
  5142. }
  5143. }
  5144. }
  5145. $devConstraints = array();
  5146. if (0 === \count($intervals['branches']['names'])) {
  5147. if ($intervals['branches']['exclude']) {
  5148. if ($hasNumericMatchAll) {
  5149. return new MatchAllConstraint;
  5150. }
  5151. }
  5152. } else {
  5153. foreach ($intervals['branches']['names'] as $branchName) {
  5154. if ($intervals['branches']['exclude']) {
  5155. $devConstraints[] = new Constraint('!=', $branchName);
  5156. } else {
  5157. $devConstraints[] = new Constraint('==', $branchName);
  5158. }
  5159. }
  5160. if ($intervals['branches']['exclude']) {
  5161. if (\count($constraints) > 1) {
  5162. return new MultiConstraint(array_merge(
  5163. array(new MultiConstraint($constraints, false)),
  5164. $devConstraints
  5165. ), true);
  5166. }
  5167. if (\count($constraints) === 1 && (string)$constraints[0] === (string)Interval::fromZero()) {
  5168. if (\count($devConstraints) > 1) {
  5169. return new MultiConstraint($devConstraints, true);
  5170. }
  5171. return $devConstraints[0];
  5172. }
  5173. return new MultiConstraint(array_merge($constraints, $devConstraints), true);
  5174. }
  5175. $constraints = array_merge($constraints, $devConstraints);
  5176. }
  5177. if (\count($constraints) > 1) {
  5178. return new MultiConstraint($constraints, false);
  5179. }
  5180. if (\count($constraints) === 1) {
  5181. return $constraints[0];
  5182. }
  5183. return new MatchNoneConstraint;
  5184. }
  5185. /**
  5186. @phpstan-return
  5187. */
  5188. public static function get(ConstraintInterface $constraint)
  5189. {
  5190. $key = (string) $constraint;
  5191. if (!isset(self::$intervalsCache[$key])) {
  5192. self::$intervalsCache[$key] = self::generateIntervals($constraint);
  5193. }
  5194. return self::$intervalsCache[$key];
  5195. }
  5196. /**
  5197. @phpstan-return
  5198. */
  5199. private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false)
  5200. {
  5201. if ($constraint instanceof MatchAllConstraint) {
  5202. return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
  5203. }
  5204. if ($constraint instanceof MatchNoneConstraint) {
  5205. return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => false));
  5206. }
  5207. if ($constraint instanceof Constraint) {
  5208. return self::generateSingleConstraintIntervals($constraint);
  5209. }
  5210. if (!$constraint instanceof MultiConstraint) {
  5211. throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got '.\get_class($constraint).'.');
  5212. }
  5213. $constraints = $constraint->getConstraints();
  5214. $numericGroups = array();
  5215. $constraintBranches = array();
  5216. foreach ($constraints as $c) {
  5217. $res = self::get($c);
  5218. $numericGroups[] = $res['numeric'];
  5219. $constraintBranches[] = $res['branches'];
  5220. }
  5221. if ($constraint->isDisjunctive()) {
  5222. $branches = Interval::noDev();
  5223. foreach ($constraintBranches as $b) {
  5224. if ($b['exclude']) {
  5225. if ($branches['exclude']) {
  5226. $branches['names'] = array_intersect($branches['names'], $b['names']);
  5227. } else {
  5228. $branches['exclude'] = true;
  5229. $branches['names'] = array_diff($b['names'], $branches['names']);
  5230. }
  5231. } else {
  5232. if ($branches['exclude']) {
  5233. $branches['names'] = array_diff($branches['names'], $b['names']);
  5234. } else {
  5235. $branches['names'] = array_merge($branches['names'], $b['names']);
  5236. }
  5237. }
  5238. }
  5239. } else {
  5240. $branches = Interval::anyDev();
  5241. foreach ($constraintBranches as $b) {
  5242. if ($b['exclude']) {
  5243. if ($branches['exclude']) {
  5244. $branches['names'] = array_merge($branches['names'], $b['names']);
  5245. } else {
  5246. $branches['names'] = array_diff($branches['names'], $b['names']);
  5247. }
  5248. } else {
  5249. if ($branches['exclude']) {
  5250. $branches['names'] = array_diff($b['names'], $branches['names']);
  5251. $branches['exclude'] = false;
  5252. } else {
  5253. $branches['names'] = array_intersect($branches['names'], $b['names']);
  5254. }
  5255. }
  5256. }
  5257. }
  5258. $branches['names'] = array_unique($branches['names']);
  5259. if (\count($numericGroups) === 1) {
  5260. return array('numeric' => $numericGroups[0], 'branches' => $branches);
  5261. }
  5262. $borders = array();
  5263. foreach ($numericGroups as $group) {
  5264. foreach ($group as $interval) {
  5265. $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start');
  5266. $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end');
  5267. }
  5268. }
  5269. $opSortOrder = self::$opSortOrder;
  5270. usort($borders, function ($a, $b) use ($opSortOrder) {
  5271. $order = version_compare($a['version'], $b['version']);
  5272. if ($order === 0) {
  5273. return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
  5274. }
  5275. return $order;
  5276. });
  5277. $activeIntervals = 0;
  5278. $intervals = array();
  5279. $index = 0;
  5280. $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
  5281. $start = null;
  5282. foreach ($borders as $border) {
  5283. if ($border['side'] === 'start') {
  5284. $activeIntervals++;
  5285. } else {
  5286. $activeIntervals--;
  5287. }
  5288. if (!$start && $activeIntervals >= $activationThreshold) {
  5289. $start = new Constraint($border['operator'], $border['version']);
  5290. } elseif ($start && $activeIntervals < $activationThreshold) {
  5291. if (
  5292. version_compare($start->getVersion(), $border['version'], '=')
  5293. && (
  5294. ($start->getOperator() === '>' && $border['operator'] === '<=')
  5295. || ($start->getOperator() === '>=' && $border['operator'] === '<')
  5296. )
  5297. ) {
  5298. unset($intervals[$index]);
  5299. } else {
  5300. $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
  5301. $index++;
  5302. if ($stopOnFirstValidInterval) {
  5303. break;
  5304. }
  5305. }
  5306. $start = null;
  5307. }
  5308. }
  5309. return array('numeric' => $intervals, 'branches' => $branches);
  5310. }
  5311. /**
  5312. @phpstan-return
  5313. */
  5314. private static function generateSingleConstraintIntervals(Constraint $constraint)
  5315. {
  5316. $op = $constraint->getOperator();
  5317. if (strpos($constraint->getVersion(), 'dev-') === 0) {
  5318. $intervals = array();
  5319. $branches = array('names' => array(), 'exclude' => false);
  5320. if ($op === '!=') {
  5321. $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity());
  5322. $branches = array('names' => array($constraint->getVersion()), 'exclude' => true);
  5323. } elseif ($op === '==') {
  5324. $branches['names'][] = $constraint->getVersion();
  5325. }
  5326. return array(
  5327. 'numeric' => $intervals,
  5328. 'branches' => $branches,
  5329. );
  5330. }
  5331. if ($op[0] === '>') {
  5332. return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev());
  5333. }
  5334. if ($op[0] === '<') {
  5335. return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev());
  5336. }
  5337. if ($op === '!=') {
  5338. return array('numeric' => array(
  5339. new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())),
  5340. new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity()),
  5341. ), 'branches' => Interval::anyDev());
  5342. }
  5343. return array('numeric' => array(
  5344. new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion())),
  5345. ), 'branches' => Interval::noDev());
  5346. }
  5347. }
  5348. <?php
  5349. namespace Composer\Semver;
  5350. use Composer\Semver\Constraint\Constraint;
  5351. class Semver
  5352. {
  5353. const SORT_ASC = 1;
  5354. const SORT_DESC = -1;
  5355. private static $versionParser;
  5356. public static function satisfies($version, $constraints)
  5357. {
  5358. if (null === self::$versionParser) {
  5359. self::$versionParser = new VersionParser();
  5360. }
  5361. $versionParser = self::$versionParser;
  5362. $provider = new Constraint('==', $versionParser->normalize($version));
  5363. $parsedConstraints = $versionParser->parseConstraints($constraints);
  5364. return $parsedConstraints->matches($provider);
  5365. }
  5366. public static function satisfiedBy(array $versions, $constraints)
  5367. {
  5368. $versions = array_filter($versions, function ($version) use ($constraints) {
  5369. return Semver::satisfies($version, $constraints);
  5370. });
  5371. return array_values($versions);
  5372. }
  5373. public static function sort(array $versions)
  5374. {
  5375. return self::usort($versions, self::SORT_ASC);
  5376. }
  5377. public static function rsort(array $versions)
  5378. {
  5379. return self::usort($versions, self::SORT_DESC);
  5380. }
  5381. private static function usort(array $versions, $direction)
  5382. {
  5383. if (null === self::$versionParser) {
  5384. self::$versionParser = new VersionParser();
  5385. }
  5386. $versionParser = self::$versionParser;
  5387. $normalized = array();
  5388. foreach ($versions as $key => $version) {
  5389. $normalizedVersion = $versionParser->normalize($version);
  5390. $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion);
  5391. $normalized[] = array($normalizedVersion, $key);
  5392. }
  5393. usort($normalized, function (array $left, array $right) use ($direction) {
  5394. if ($left[0] === $right[0]) {
  5395. return 0;
  5396. }
  5397. if (Comparator::lessThan($left[0], $right[0])) {
  5398. return -$direction;
  5399. }
  5400. return $direction;
  5401. });
  5402. $sorted = array();
  5403. foreach ($normalized as $item) {
  5404. $sorted[] = $versions[$item[1]];
  5405. }
  5406. return $sorted;
  5407. }
  5408. }
  5409. <?php
  5410. namespace Composer\Semver;
  5411. use Composer\Semver\Constraint\ConstraintInterface;
  5412. use Composer\Semver\Constraint\MatchAllConstraint;
  5413. use Composer\Semver\Constraint\MultiConstraint;
  5414. use Composer\Semver\Constraint\Constraint;
  5415. class VersionParser
  5416. {
  5417. private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
  5418. private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
  5419. /**
  5420. @phpstan-return
  5421. */
  5422. public static function parseStability($version)
  5423. {
  5424. $version = (string) preg_replace('{#.+$}', '', (string) $version);
  5425. if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
  5426. return 'dev';
  5427. }
  5428. preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
  5429. if (!empty($match[3])) {
  5430. return 'dev';
  5431. }
  5432. if (!empty($match[1])) {
  5433. if ('beta' === $match[1] || 'b' === $match[1]) {
  5434. return 'beta';
  5435. }
  5436. if ('alpha' === $match[1] || 'a' === $match[1]) {
  5437. return 'alpha';
  5438. }
  5439. if ('rc' === $match[1]) {
  5440. return 'RC';
  5441. }
  5442. }
  5443. return 'stable';
  5444. }
  5445. /**
  5446. @phpstan-return
  5447. */
  5448. public static function normalizeStability($stability)
  5449. {
  5450. $stability = strtolower((string) $stability);
  5451. if (!in_array($stability, array('stable', 'rc', 'beta', 'alpha', 'dev'), true)) {
  5452. throw new \InvalidArgumentException('Invalid stability string "'.$stability.'", expected one of stable, RC, beta, alpha or dev');
  5453. }
  5454. return $stability === 'rc' ? 'RC' : $stability;
  5455. }
  5456. public function normalize($version, $fullVersion = null)
  5457. {
  5458. $version = trim((string) $version);
  5459. $origVersion = $version;
  5460. if (null === $fullVersion) {
  5461. $fullVersion = $version;
  5462. }
  5463. if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
  5464. $version = $match[1];
  5465. }
  5466. if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
  5467. $version = substr($version, 0, strlen($version) - strlen($match[0]));
  5468. }
  5469. if (\in_array($version, array('master', 'trunk', 'default'), true)) {
  5470. $version = 'dev-' . $version;
  5471. }
  5472. if (stripos($version, 'dev-') === 0) {
  5473. return 'dev-' . substr($version, 4);
  5474. }
  5475. if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
  5476. $version = $match[1];
  5477. }
  5478. if (preg_match('{^v?(\d{1,5}+)(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
  5479. $version = $matches[1]
  5480. . (!empty($matches[2]) ? $matches[2] : '.0')
  5481. . (!empty($matches[3]) ? $matches[3] : '.0')
  5482. . (!empty($matches[4]) ? $matches[4] : '.0');
  5483. $index = 5;
  5484. } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
  5485. $version = (string) preg_replace('{\D}', '.', $matches[1]);
  5486. $index = 2;
  5487. }
  5488. if (isset($index)) {
  5489. if (!empty($matches[$index])) {
  5490. if ('stable' === $matches[$index]) {
  5491. return $version;
  5492. }
  5493. $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
  5494. }
  5495. if (!empty($matches[$index + 2])) {
  5496. $version .= '-dev';
  5497. }
  5498. return $version;
  5499. }
  5500. if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
  5501. try {
  5502. $normalized = $this->normalizeBranch($match[1]);
  5503. if (strpos($normalized, 'dev-') === false) {
  5504. return $normalized;
  5505. }
  5506. } catch (\Exception $e) {
  5507. }
  5508. }
  5509. $extraMessage = '';
  5510. if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) {
  5511. $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
  5512. } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) {
  5513. $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
  5514. }
  5515. throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
  5516. }
  5517. public function parseNumericAliasPrefix($branch)
  5518. {
  5519. if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', (string) $branch, $matches)) {
  5520. return $matches['version'] . '.';
  5521. }
  5522. return false;
  5523. }
  5524. public function normalizeBranch($name)
  5525. {
  5526. $name = trim((string) $name);
  5527. if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
  5528. $version = '';
  5529. for ($i = 1; $i < 5; ++$i) {
  5530. $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
  5531. }
  5532. return str_replace('x', '9999999', $version) . '-dev';
  5533. }
  5534. return 'dev-' . $name;
  5535. }
  5536. public function normalizeDefaultBranch($name)
  5537. {
  5538. if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') {
  5539. return '9999999-dev';
  5540. }
  5541. return (string) $name;
  5542. }
  5543. public function parseConstraints($constraints)
  5544. {
  5545. $prettyConstraint = (string) $constraints;
  5546. $orConstraints = preg_split('{\s*\|\|?\s*}', trim((string) $constraints));
  5547. if (false === $orConstraints) {
  5548. throw new \RuntimeException('Failed to preg_split string: '.$constraints);
  5549. }
  5550. $orGroups = array();
  5551. foreach ($orConstraints as $orConstraint) {
  5552. $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
  5553. if (false === $andConstraints) {
  5554. throw new \RuntimeException('Failed to preg_split string: '.$orConstraint);
  5555. }
  5556. if (\count($andConstraints) > 1) {
  5557. $constraintObjects = array();
  5558. foreach ($andConstraints as $andConstraint) {
  5559. foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
  5560. $constraintObjects[] = $parsedAndConstraint;
  5561. }
  5562. }
  5563. } else {
  5564. $constraintObjects = $this->parseConstraint($andConstraints[0]);
  5565. }
  5566. if (1 === \count($constraintObjects)) {
  5567. $constraint = $constraintObjects[0];
  5568. } else {
  5569. $constraint = new MultiConstraint($constraintObjects);
  5570. }
  5571. $orGroups[] = $constraint;
  5572. }
  5573. $parsedConstraint = MultiConstraint::create($orGroups, false);
  5574. $parsedConstraint->setPrettyString($prettyConstraint);
  5575. return $parsedConstraint;
  5576. }
  5577. /**
  5578. @phpstan-return
  5579. */
  5580. private function parseConstraint($constraint)
  5581. {
  5582. if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
  5583. $constraint = $match[1];
  5584. }
  5585. if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
  5586. $constraint = '' !== $match[1] ? $match[1] : '*';
  5587. if ($match[2] !== 'stable') {
  5588. $stabilityModifier = $match[2];
  5589. }
  5590. }
  5591. if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
  5592. $constraint = $match[1];
  5593. }
  5594. if (preg_match('{^(v)?[xX*](\.[xX*])*$}i', $constraint, $match)) {
  5595. if (!empty($match[1]) || !empty($match[2])) {
  5596. return array(new Constraint('>=', '0.0.0.0-dev'));
  5597. }
  5598. return array(new MatchAllConstraint());
  5599. }
  5600. $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';
  5601. if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
  5602. if (strpos($constraint, '~>') === 0) {
  5603. throw new \UnexpectedValueException(
  5604. 'Could not parse version constraint ' . $constraint . ': ' .
  5605. 'Invalid operator "~>", you probably meant to use the "~" operator'
  5606. );
  5607. }
  5608. if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
  5609. $position = 4;
  5610. } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
  5611. $position = 3;
  5612. } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
  5613. $position = 2;
  5614. } else {
  5615. $position = 1;
  5616. }
  5617. if (!empty($matches[8])) {
  5618. $position++;
  5619. }
  5620. $stabilitySuffix = '';
  5621. if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
  5622. $stabilitySuffix .= '-dev';
  5623. }
  5624. $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
  5625. $lowerBound = new Constraint('>=', $lowVersion);
  5626. $highPosition = max(1, $position - 1);
  5627. $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
  5628. $upperBound = new Constraint('<', $highVersion);
  5629. return array(
  5630. $lowerBound,
  5631. $upperBound,
  5632. );
  5633. }
  5634. if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
  5635. if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
  5636. $position = 1;
  5637. } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
  5638. $position = 2;
  5639. } else {
  5640. $position = 3;
  5641. }
  5642. $stabilitySuffix = '';
  5643. if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
  5644. $stabilitySuffix .= '-dev';
  5645. }
  5646. $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
  5647. $lowerBound = new Constraint('>=', $lowVersion);
  5648. $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
  5649. $upperBound = new Constraint('<', $highVersion);
  5650. return array(
  5651. $lowerBound,
  5652. $upperBound,
  5653. );
  5654. }
  5655. if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
  5656. if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
  5657. $position = 3;
  5658. } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
  5659. $position = 2;
  5660. } else {
  5661. $position = 1;
  5662. }
  5663. $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
  5664. $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
  5665. if ($lowVersion === '0.0.0.0-dev') {
  5666. return array(new Constraint('<', $highVersion));
  5667. }
  5668. return array(
  5669. new Constraint('>=', $lowVersion),
  5670. new Constraint('<', $highVersion),
  5671. );
  5672. }
  5673. if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
  5674. $lowStabilitySuffix = '';
  5675. if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
  5676. $lowStabilitySuffix = '-dev';
  5677. }
  5678. $lowVersion = $this->normalize($matches['from']);
  5679. $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
  5680. $empty = function ($x) {
  5681. return ($x === 0 || $x === '0') ? false : empty($x);
  5682. };
  5683. if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
  5684. $highVersion = $this->normalize($matches['to']);
  5685. $upperBound = new Constraint('<=', $highVersion);
  5686. } else {
  5687. $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
  5688. $this->normalize($matches['to']);
  5689. $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
  5690. $upperBound = new Constraint('<', $highVersion);
  5691. }
  5692. return array(
  5693. $lowerBound,
  5694. $upperBound,
  5695. );
  5696. }
  5697. if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
  5698. try {
  5699. try {
  5700. $version = $this->normalize($matches[2]);
  5701. } catch (\UnexpectedValueException $e) {
  5702. if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
  5703. $version = $this->normalize('dev-'.substr($matches[2], 0, -4));
  5704. } else {
  5705. throw $e;
  5706. }
  5707. }
  5708. $op = $matches[1] ?: '=';
  5709. if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
  5710. $version .= '-' . $stabilityModifier;
  5711. } elseif ('<' === $op || '>=' === $op) {
  5712. if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
  5713. if (strpos($matches[2], 'dev-') !== 0) {
  5714. $version .= '-dev';
  5715. }
  5716. }
  5717. }
  5718. return array(new Constraint($matches[1] ?: '=', $version));
  5719. } catch (\Exception $e) {
  5720. }
  5721. }
  5722. $message = 'Could not parse version constraint ' . $constraint;
  5723. if (isset($e)) {
  5724. $message .= ': ' . $e->getMessage();
  5725. }
  5726. throw new \UnexpectedValueException($message);
  5727. }
  5728. /**
  5729. @phpstan-param
  5730. */
  5731. private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0')
  5732. {
  5733. for ($i = 4; $i > 0; --$i) {
  5734. if ($i > $position) {
  5735. $matches[$i] = $pad;
  5736. } elseif ($i === $position && $increment) {
  5737. $matches[$i] += $increment;
  5738. if ($matches[$i] < 0) {
  5739. $matches[$i] = $pad;
  5740. --$position;
  5741. if ($i === 1) {
  5742. return null;
  5743. }
  5744. }
  5745. }
  5746. }
  5747. return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
  5748. }
  5749. private function expandStability($stability)
  5750. {
  5751. $stability = strtolower($stability);
  5752. switch ($stability) {
  5753. case 'a':
  5754. return 'alpha';
  5755. case 'b':
  5756. return 'beta';
  5757. case 'p':
  5758. case 'pl':
  5759. return 'patch';
  5760. case 'rc':
  5761. return 'RC';
  5762. default:
  5763. return $stability;
  5764. }
  5765. }
  5766. }
  5767. <?php
  5768. namespace Composer\Semver\Constraint;
  5769. interface ConstraintInterface
  5770. {
  5771. public function matches(ConstraintInterface $provider);
  5772. /**
  5773. @phpstan-param
  5774. */
  5775. public function compile($otherOperator);
  5776. public function getUpperBound();
  5777. public function getLowerBound();
  5778. public function getPrettyString();
  5779. public function setPrettyString($prettyString);
  5780. public function __toString();
  5781. }
  5782. <?php
  5783. namespace Composer\Semver\Constraint;
  5784. class MultiConstraint implements ConstraintInterface
  5785. {
  5786. /**
  5787. @phpstan-var
  5788. */
  5789. protected $constraints;
  5790. protected $prettyString;
  5791. protected $string;
  5792. protected $conjunctive;
  5793. protected $lowerBound;
  5794. protected $upperBound;
  5795. public function __construct(array $constraints, $conjunctive = true)
  5796. {
  5797. if (\count($constraints) < 2) {
  5798. throw new \InvalidArgumentException(
  5799. 'Must provide at least two constraints for a MultiConstraint. Use '.
  5800. 'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use '.
  5801. 'MultiConstraint::create() which optimizes and handles those cases automatically.'
  5802. );
  5803. }
  5804. $this->constraints = $constraints;
  5805. $this->conjunctive = $conjunctive;
  5806. }
  5807. public function getConstraints()
  5808. {
  5809. return $this->constraints;
  5810. }
  5811. public function isConjunctive()
  5812. {
  5813. return $this->conjunctive;
  5814. }
  5815. public function isDisjunctive()
  5816. {
  5817. return !$this->conjunctive;
  5818. }
  5819. public function compile($otherOperator)
  5820. {
  5821. $parts = array();
  5822. foreach ($this->constraints as $constraint) {
  5823. $code = $constraint->compile($otherOperator);
  5824. if ($code === 'true') {
  5825. if (!$this->conjunctive) {
  5826. return 'true';
  5827. }
  5828. } elseif ($code === 'false') {
  5829. if ($this->conjunctive) {
  5830. return 'false';
  5831. }
  5832. } else {
  5833. $parts[] = '('.$code.')';
  5834. }
  5835. }
  5836. if (!$parts) {
  5837. return $this->conjunctive ? 'true' : 'false';
  5838. }
  5839. return $this->conjunctive ? implode('&&', $parts) : implode('||', $parts);
  5840. }
  5841. public function matches(ConstraintInterface $provider)
  5842. {
  5843. if (false === $this->conjunctive) {
  5844. foreach ($this->constraints as $constraint) {
  5845. if ($provider->matches($constraint)) {
  5846. return true;
  5847. }
  5848. }
  5849. return false;
  5850. }
  5851. if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) {
  5852. return $provider->matches($this);
  5853. }
  5854. foreach ($this->constraints as $constraint) {
  5855. if (!$provider->matches($constraint)) {
  5856. return false;
  5857. }
  5858. }
  5859. return true;
  5860. }
  5861. public function setPrettyString($prettyString)
  5862. {
  5863. $this->prettyString = $prettyString;
  5864. }
  5865. public function getPrettyString()
  5866. {
  5867. if ($this->prettyString) {
  5868. return $this->prettyString;
  5869. }
  5870. return (string) $this;
  5871. }
  5872. public function __toString()
  5873. {
  5874. if ($this->string !== null) {
  5875. return $this->string;
  5876. }
  5877. $constraints = array();
  5878. foreach ($this->constraints as $constraint) {
  5879. $constraints[] = (string) $constraint;
  5880. }
  5881. return $this->string = '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
  5882. }
  5883. public function getLowerBound()
  5884. {
  5885. $this->extractBounds();
  5886. if (null === $this->lowerBound) {
  5887. throw new \LogicException('extractBounds should have populated the lowerBound property');
  5888. }
  5889. return $this->lowerBound;
  5890. }
  5891. public function getUpperBound()
  5892. {
  5893. $this->extractBounds();
  5894. if (null === $this->upperBound) {
  5895. throw new \LogicException('extractBounds should have populated the upperBound property');
  5896. }
  5897. return $this->upperBound;
  5898. }
  5899. public static function create(array $constraints, $conjunctive = true)
  5900. {
  5901. if (0 === \count($constraints)) {
  5902. return new MatchAllConstraint();
  5903. }
  5904. if (1 === \count($constraints)) {
  5905. return $constraints[0];
  5906. }
  5907. $optimized = self::optimizeConstraints($constraints, $conjunctive);
  5908. if ($optimized !== null) {
  5909. list($constraints, $conjunctive) = $optimized;
  5910. if (\count($constraints) === 1) {
  5911. return $constraints[0];
  5912. }
  5913. }
  5914. return new self($constraints, $conjunctive);
  5915. }
  5916. /**
  5917. @phpstan-return
  5918. */
  5919. private static function optimizeConstraints(array $constraints, $conjunctive)
  5920. {
  5921. if (!$conjunctive) {
  5922. $left = $constraints[0];
  5923. $mergedConstraints = array();
  5924. $optimized = false;
  5925. for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
  5926. $right = $constraints[$i];
  5927. if (
  5928. $left instanceof self
  5929. && $left->conjunctive
  5930. && $right instanceof self
  5931. && $right->conjunctive
  5932. && \count($left->constraints) === 2
  5933. && \count($right->constraints) === 2
  5934. && ($left0 = (string) $left->constraints[0])
  5935. && $left0[0] === '>' && $left0[1] === '='
  5936. && ($left1 = (string) $left->constraints[1])
  5937. && $left1[0] === '<'
  5938. && ($right0 = (string) $right->constraints[0])
  5939. && $right0[0] === '>' && $right0[1] === '='
  5940. && ($right1 = (string) $right->constraints[1])
  5941. && $right1[0] === '<'
  5942. && substr($left1, 2) === substr($right0, 3)
  5943. ) {
  5944. $optimized = true;
  5945. $left = new MultiConstraint(
  5946. array(
  5947. $left->constraints[0],
  5948. $right->constraints[1],
  5949. ),
  5950. true);
  5951. } else {
  5952. $mergedConstraints[] = $left;
  5953. $left = $right;
  5954. }
  5955. }
  5956. if ($optimized) {
  5957. $mergedConstraints[] = $left;
  5958. return array($mergedConstraints, false);
  5959. }
  5960. }
  5961. return null;
  5962. }
  5963. private function extractBounds()
  5964. {
  5965. if (null !== $this->lowerBound) {
  5966. return;
  5967. }
  5968. foreach ($this->constraints as $constraint) {
  5969. if (null === $this->lowerBound || null === $this->upperBound) {
  5970. $this->lowerBound = $constraint->getLowerBound();
  5971. $this->upperBound = $constraint->getUpperBound();
  5972. continue;
  5973. }
  5974. if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) {
  5975. $this->lowerBound = $constraint->getLowerBound();
  5976. }
  5977. if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) {
  5978. $this->upperBound = $constraint->getUpperBound();
  5979. }
  5980. }
  5981. }
  5982. }
  5983. <?php
  5984. namespace Composer\Semver\Constraint;
  5985. class Constraint implements ConstraintInterface
  5986. {
  5987. const OP_EQ = 0;
  5988. const OP_LT = 1;
  5989. const OP_LE = 2;
  5990. const OP_GT = 3;
  5991. const OP_GE = 4;
  5992. const OP_NE = 5;
  5993. const STR_OP_EQ = '==';
  5994. const STR_OP_EQ_ALT = '=';
  5995. const STR_OP_LT = '<';
  5996. const STR_OP_LE = '<=';
  5997. const STR_OP_GT = '>';
  5998. const STR_OP_GE = '>=';
  5999. const STR_OP_NE = '!=';
  6000. const STR_OP_NE_ALT = '<>';
  6001. /**
  6002. @phpstan-var
  6003. */
  6004. private static $transOpStr = array(
  6005. '=' => self::OP_EQ,
  6006. '==' => self::OP_EQ,
  6007. '<' => self::OP_LT,
  6008. '<=' => self::OP_LE,
  6009. '>' => self::OP_GT,
  6010. '>=' => self::OP_GE,
  6011. '<>' => self::OP_NE,
  6012. '!=' => self::OP_NE,
  6013. );
  6014. /**
  6015. @phpstan-var
  6016. */
  6017. private static $transOpInt = array(
  6018. self::OP_EQ => '==',
  6019. self::OP_LT => '<',
  6020. self::OP_LE => '<=',
  6021. self::OP_GT => '>',
  6022. self::OP_GE => '>=',
  6023. self::OP_NE => '!=',
  6024. );
  6025. /**
  6026. @phpstan-var
  6027. */
  6028. protected $operator;
  6029. protected $version;
  6030. protected $prettyString;
  6031. protected $lowerBound;
  6032. protected $upperBound;
  6033. /**
  6034. @phpstan-param
  6035. */
  6036. public function __construct($operator, $version)
  6037. {
  6038. if (!isset(self::$transOpStr[$operator])) {
  6039. throw new \InvalidArgumentException(sprintf(
  6040. 'Invalid operator "%s" given, expected one of: %s',
  6041. $operator,
  6042. implode(', ', self::getSupportedOperators())
  6043. ));
  6044. }
  6045. $this->operator = self::$transOpStr[$operator];
  6046. $this->version = $version;
  6047. }
  6048. public function getVersion()
  6049. {
  6050. return $this->version;
  6051. }
  6052. /**
  6053. @phpstan-return
  6054. */
  6055. public function getOperator()
  6056. {
  6057. return self::$transOpInt[$this->operator];
  6058. }
  6059. public function matches(ConstraintInterface $provider)
  6060. {
  6061. if ($provider instanceof self) {
  6062. return $this->matchSpecific($provider);
  6063. }
  6064. return $provider->matches($this);
  6065. }
  6066. public function setPrettyString($prettyString)
  6067. {
  6068. $this->prettyString = $prettyString;
  6069. }
  6070. public function getPrettyString()
  6071. {
  6072. if ($this->prettyString) {
  6073. return $this->prettyString;
  6074. }
  6075. return $this->__toString();
  6076. }
  6077. /**
  6078. @phpstan-return
  6079. */
  6080. public static function getSupportedOperators()
  6081. {
  6082. return array_keys(self::$transOpStr);
  6083. }
  6084. /**
  6085. @phpstan-param
  6086. @phpstan-return
  6087. */
  6088. public static function getOperatorConstant($operator)
  6089. {
  6090. return self::$transOpStr[$operator];
  6091. }
  6092. /**
  6093. @phpstan-param
  6094. */
  6095. public function versionCompare($a, $b, $operator, $compareBranches = false)
  6096. {
  6097. if (!isset(self::$transOpStr[$operator])) {
  6098. throw new \InvalidArgumentException(sprintf(
  6099. 'Invalid operator "%s" given, expected one of: %s',
  6100. $operator,
  6101. implode(', ', self::getSupportedOperators())
  6102. ));
  6103. }
  6104. $aIsBranch = strpos($a, 'dev-') === 0;
  6105. $bIsBranch = strpos($b, 'dev-') === 0;
  6106. if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
  6107. return $a !== $b;
  6108. }
  6109. if ($aIsBranch && $bIsBranch) {
  6110. return $operator === '==' && $a === $b;
  6111. }
  6112. if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
  6113. return false;
  6114. }
  6115. return \version_compare($a, $b, $operator);
  6116. }
  6117. public function compile($otherOperator)
  6118. {
  6119. if (strpos($this->version, 'dev-') === 0) {
  6120. if (self::OP_EQ === $this->operator) {
  6121. if (self::OP_EQ === $otherOperator) {
  6122. return sprintf('$b && $v === %s', \var_export($this->version, true));
  6123. }
  6124. if (self::OP_NE === $otherOperator) {
  6125. return sprintf('!$b || $v !== %s', \var_export($this->version, true));
  6126. }
  6127. return 'false';
  6128. }
  6129. if (self::OP_NE === $this->operator) {
  6130. if (self::OP_EQ === $otherOperator) {
  6131. return sprintf('!$b || $v !== %s', \var_export($this->version, true));
  6132. }
  6133. if (self::OP_NE === $otherOperator) {
  6134. return 'true';
  6135. }
  6136. return '!$b';
  6137. }
  6138. return 'false';
  6139. }
  6140. if (self::OP_EQ === $this->operator) {
  6141. if (self::OP_EQ === $otherOperator) {
  6142. return sprintf('\version_compare($v, %s, \'==\')', \var_export($this->version, true));
  6143. }
  6144. if (self::OP_NE === $otherOperator) {
  6145. return sprintf('$b || \version_compare($v, %s, \'!=\')', \var_export($this->version, true));
  6146. }
  6147. return sprintf('!$b && \version_compare(%s, $v, \'%s\')', \var_export($this->version, true), self::$transOpInt[$otherOperator]);
  6148. }
  6149. if (self::OP_NE === $this->operator) {
  6150. if (self::OP_EQ === $otherOperator) {
  6151. return sprintf('$b || (!$b && \version_compare($v, %s, \'!=\'))', \var_export($this->version, true));
  6152. }
  6153. if (self::OP_NE === $otherOperator) {
  6154. return 'true';
  6155. }
  6156. return '!$b';
  6157. }
  6158. if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
  6159. if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
  6160. return '!$b';
  6161. }
  6162. } else {
  6163. if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
  6164. return '!$b';
  6165. }
  6166. }
  6167. if (self::OP_NE === $otherOperator) {
  6168. return 'true';
  6169. }
  6170. $codeComparison = sprintf('\version_compare($v, %s, \'%s\')', \var_export($this->version, true), self::$transOpInt[$this->operator]);
  6171. if ($this->operator === self::OP_LE) {
  6172. if ($otherOperator === self::OP_GT) {
  6173. return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
  6174. }
  6175. } elseif ($this->operator === self::OP_GE) {
  6176. if ($otherOperator === self::OP_LT) {
  6177. return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
  6178. }
  6179. }
  6180. return sprintf('!$b && %s', $codeComparison);
  6181. }
  6182. public function matchSpecific(Constraint $provider, $compareBranches = false)
  6183. {
  6184. $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
  6185. $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
  6186. $isEqualOp = self::OP_EQ === $this->operator;
  6187. $isNonEqualOp = self::OP_NE === $this->operator;
  6188. $isProviderEqualOp = self::OP_EQ === $provider->operator;
  6189. $isProviderNonEqualOp = self::OP_NE === $provider->operator;
  6190. if ($isNonEqualOp || $isProviderNonEqualOp) {
  6191. if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && strpos($provider->version, 'dev-') === 0) {
  6192. return false;
  6193. }
  6194. if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && strpos($this->version, 'dev-') === 0) {
  6195. return false;
  6196. }
  6197. if (!$isEqualOp && !$isProviderEqualOp) {
  6198. return true;
  6199. }
  6200. return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
  6201. }
  6202. if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
  6203. return !(strpos($this->version, 'dev-') === 0 || strpos($provider->version, 'dev-') === 0);
  6204. }
  6205. $version1 = $isEqualOp ? $this->version : $provider->version;
  6206. $version2 = $isEqualOp ? $provider->version : $this->version;
  6207. $operator = $isEqualOp ? $provider->operator : $this->operator;
  6208. if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
  6209. return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp
  6210. && self::$transOpInt[$this->operator] !== $noEqualOp
  6211. && \version_compare($provider->version, $this->version, '=='));
  6212. }
  6213. return false;
  6214. }
  6215. public function __toString()
  6216. {
  6217. return self::$transOpInt[$this->operator] . ' ' . $this->version;
  6218. }
  6219. public function getLowerBound()
  6220. {
  6221. $this->extractBounds();
  6222. return $this->lowerBound;
  6223. }
  6224. public function getUpperBound()
  6225. {
  6226. $this->extractBounds();
  6227. return $this->upperBound;
  6228. }
  6229. private function extractBounds()
  6230. {
  6231. if (null !== $this->lowerBound) {
  6232. return;
  6233. }
  6234. if (strpos($this->version, 'dev-') === 0) {
  6235. $this->lowerBound = Bound::zero();
  6236. $this->upperBound = Bound::positiveInfinity();
  6237. return;
  6238. }
  6239. switch ($this->operator) {
  6240. case self::OP_EQ:
  6241. $this->lowerBound = new Bound($this->version, true);
  6242. $this->upperBound = new Bound($this->version, true);
  6243. break;
  6244. case self::OP_LT:
  6245. $this->lowerBound = Bound::zero();
  6246. $this->upperBound = new Bound($this->version, false);
  6247. break;
  6248. case self::OP_LE:
  6249. $this->lowerBound = Bound::zero();
  6250. $this->upperBound = new Bound($this->version, true);
  6251. break;
  6252. case self::OP_GT:
  6253. $this->lowerBound = new Bound($this->version, false);
  6254. $this->upperBound = Bound::positiveInfinity();
  6255. break;
  6256. case self::OP_GE:
  6257. $this->lowerBound = new Bound($this->version, true);
  6258. $this->upperBound = Bound::positiveInfinity();
  6259. break;
  6260. case self::OP_NE:
  6261. $this->lowerBound = Bound::zero();
  6262. $this->upperBound = Bound::positiveInfinity();
  6263. break;
  6264. }
  6265. }
  6266. }
  6267. <?php
  6268. namespace Composer\Semver\Constraint;
  6269. class MatchAllConstraint implements ConstraintInterface
  6270. {
  6271. protected $prettyString;
  6272. public function matches(ConstraintInterface $provider)
  6273. {
  6274. return true;
  6275. }
  6276. public function compile($otherOperator)
  6277. {
  6278. return 'true';
  6279. }
  6280. public function setPrettyString($prettyString)
  6281. {
  6282. $this->prettyString = $prettyString;
  6283. }
  6284. public function getPrettyString()
  6285. {
  6286. if ($this->prettyString) {
  6287. return $this->prettyString;
  6288. }
  6289. return (string) $this;
  6290. }
  6291. public function __toString()
  6292. {
  6293. return '*';
  6294. }
  6295. public function getUpperBound()
  6296. {
  6297. return Bound::positiveInfinity();
  6298. }
  6299. public function getLowerBound()
  6300. {
  6301. return Bound::zero();
  6302. }
  6303. }
  6304. <?php
  6305. namespace Composer\Semver\Constraint;
  6306. class MatchNoneConstraint implements ConstraintInterface
  6307. {
  6308. protected $prettyString;
  6309. public function matches(ConstraintInterface $provider)
  6310. {
  6311. return false;
  6312. }
  6313. public function compile($otherOperator)
  6314. {
  6315. return 'false';
  6316. }
  6317. public function setPrettyString($prettyString)
  6318. {
  6319. $this->prettyString = $prettyString;
  6320. }
  6321. public function getPrettyString()
  6322. {
  6323. if ($this->prettyString) {
  6324. return $this->prettyString;
  6325. }
  6326. return (string) $this;
  6327. }
  6328. public function __toString()
  6329. {
  6330. return '[]';
  6331. }
  6332. public function getUpperBound()
  6333. {
  6334. return new Bound('0.0.0.0-dev', false);
  6335. }
  6336. public function getLowerBound()
  6337. {
  6338. return new Bound('0.0.0.0-dev', false);
  6339. }
  6340. }
  6341. <?php
  6342. namespace Composer\Semver\Constraint;
  6343. class Bound
  6344. {
  6345. private $version;
  6346. private $isInclusive;
  6347. public function __construct($version, $isInclusive)
  6348. {
  6349. $this->version = $version;
  6350. $this->isInclusive = $isInclusive;
  6351. }
  6352. public function getVersion()
  6353. {
  6354. return $this->version;
  6355. }
  6356. public function isInclusive()
  6357. {
  6358. return $this->isInclusive;
  6359. }
  6360. public function isZero()
  6361. {
  6362. return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive();
  6363. }
  6364. public function isPositiveInfinity()
  6365. {
  6366. return $this->getVersion() === PHP_INT_MAX.'.0.0.0' && !$this->isInclusive();
  6367. }
  6368. public function compareTo(Bound $other, $operator)
  6369. {
  6370. if (!\in_array($operator, array('<', '>'), true)) {
  6371. throw new \InvalidArgumentException('Does not support any other operator other than > or <.');
  6372. }
  6373. if ($this == $other) {
  6374. return false;
  6375. }
  6376. $compareResult = version_compare($this->getVersion(), $other->getVersion());
  6377. if (0 !== $compareResult) {
  6378. return (('>' === $operator) ? 1 : -1) === $compareResult;
  6379. }
  6380. return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
  6381. }
  6382. public function __toString()
  6383. {
  6384. return sprintf(
  6385. '%s [%s]',
  6386. $this->getVersion(),
  6387. $this->isInclusive() ? 'inclusive' : 'exclusive'
  6388. );
  6389. }
  6390. public static function zero()
  6391. {
  6392. return new Bound('0.0.0.0-dev', true);
  6393. }
  6394. public static function positiveInfinity()
  6395. {
  6396. return new Bound(PHP_INT_MAX.'.0.0.0', false);
  6397. }
  6398. }
  6399. <?php
  6400. $vendorDir = dirname(__DIR__);
  6401. $baseDir = dirname($vendorDir);
  6402. return array(
  6403. 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
  6404. '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
  6405. 'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php',
  6406. '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
  6407. '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
  6408. '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
  6409. 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
  6410. '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
  6411. 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
  6412. '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
  6413. );
  6414. <?php
  6415. namespace Composer;
  6416. use Composer\Autoload\ClassLoader;
  6417. use Composer\Semver\VersionParser;
  6418. class InstalledVersions
  6419. {
  6420. private static $selfDir = null;
  6421. /**
  6422. @psalm-var
  6423. */
  6424. private static $installed;
  6425. private static $installedIsLocalDir;
  6426. private static $canGetVendors;
  6427. /**
  6428. @psalm-var
  6429. */
  6430. private static $installedByVendor = array();
  6431. /**
  6432. @psalm-return
  6433. */
  6434. public static function getInstalledPackages()
  6435. {
  6436. $packages = array();
  6437. foreach (self::getInstalled() as $installed) {
  6438. $packages[] = array_keys($installed['versions']);
  6439. }
  6440. if (1 === \count($packages)) {
  6441. return $packages[0];
  6442. }
  6443. return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
  6444. }
  6445. /**
  6446. @psalm-return
  6447. */
  6448. public static function getInstalledPackagesByType($type)
  6449. {
  6450. $packagesByType = array();
  6451. foreach (self::getInstalled() as $installed) {
  6452. foreach ($installed['versions'] as $name => $package) {
  6453. if (isset($package['type']) && $package['type'] === $type) {
  6454. $packagesByType[] = $name;
  6455. }
  6456. }
  6457. }
  6458. return $packagesByType;
  6459. }
  6460. public static function isInstalled($packageName, $includeDevRequirements = true)
  6461. {
  6462. foreach (self::getInstalled() as $installed) {
  6463. if (isset($installed['versions'][$packageName])) {
  6464. return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
  6465. }
  6466. }
  6467. return false;
  6468. }
  6469. public static function satisfies(VersionParser $parser, $packageName, $constraint)
  6470. {
  6471. $constraint = $parser->parseConstraints((string) $constraint);
  6472. $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
  6473. return $provided->matches($constraint);
  6474. }
  6475. public static function getVersionRanges($packageName)
  6476. {
  6477. foreach (self::getInstalled() as $installed) {
  6478. if (!isset($installed['versions'][$packageName])) {
  6479. continue;
  6480. }
  6481. $ranges = array();
  6482. if (isset($installed['versions'][$packageName]['pretty_version'])) {
  6483. $ranges[] = $installed['versions'][$packageName]['pretty_version'];
  6484. }
  6485. if (array_key_exists('aliases', $installed['versions'][$packageName])) {
  6486. $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
  6487. }
  6488. if (array_key_exists('replaced', $installed['versions'][$packageName])) {
  6489. $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
  6490. }
  6491. if (array_key_exists('provided', $installed['versions'][$packageName])) {
  6492. $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
  6493. }
  6494. return implode(' || ', $ranges);
  6495. }
  6496. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  6497. }
  6498. public static function getVersion($packageName)
  6499. {
  6500. foreach (self::getInstalled() as $installed) {
  6501. if (!isset($installed['versions'][$packageName])) {
  6502. continue;
  6503. }
  6504. if (!isset($installed['versions'][$packageName]['version'])) {
  6505. return null;
  6506. }
  6507. return $installed['versions'][$packageName]['version'];
  6508. }
  6509. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  6510. }
  6511. public static function getPrettyVersion($packageName)
  6512. {
  6513. foreach (self::getInstalled() as $installed) {
  6514. if (!isset($installed['versions'][$packageName])) {
  6515. continue;
  6516. }
  6517. if (!isset($installed['versions'][$packageName]['pretty_version'])) {
  6518. return null;
  6519. }
  6520. return $installed['versions'][$packageName]['pretty_version'];
  6521. }
  6522. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  6523. }
  6524. public static function getReference($packageName)
  6525. {
  6526. foreach (self::getInstalled() as $installed) {
  6527. if (!isset($installed['versions'][$packageName])) {
  6528. continue;
  6529. }
  6530. if (!isset($installed['versions'][$packageName]['reference'])) {
  6531. return null;
  6532. }
  6533. return $installed['versions'][$packageName]['reference'];
  6534. }
  6535. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  6536. }
  6537. public static function getInstallPath($packageName)
  6538. {
  6539. foreach (self::getInstalled() as $installed) {
  6540. if (!isset($installed['versions'][$packageName])) {
  6541. continue;
  6542. }
  6543. return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
  6544. }
  6545. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  6546. }
  6547. /**
  6548. @psalm-return
  6549. */
  6550. public static function getRootPackage()
  6551. {
  6552. $installed = self::getInstalled();
  6553. return $installed[0]['root'];
  6554. }
  6555. /**
  6556. @psalm-return
  6557. */
  6558. public static function getRawData()
  6559. {
  6560. @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
  6561. if (null === self::$installed) {
  6562. if (substr(__DIR__, -8, 1) !== 'C') {
  6563. self::$installed = include __DIR__ . '/installed.php';
  6564. } else {
  6565. self::$installed = array();
  6566. }
  6567. }
  6568. return self::$installed;
  6569. }
  6570. /**
  6571. @psalm-return
  6572. */
  6573. public static function getAllRawData()
  6574. {
  6575. return self::getInstalled();
  6576. }
  6577. /**
  6578. @psalm-param
  6579. */
  6580. public static function reload($data)
  6581. {
  6582. self::$installed = $data;
  6583. self::$installedByVendor = array();
  6584. self::$installedIsLocalDir = false;
  6585. }
  6586. private static function getSelfDir()
  6587. {
  6588. if (self::$selfDir === null) {
  6589. self::$selfDir = strtr(__DIR__, '\\', '/');
  6590. }
  6591. return self::$selfDir;
  6592. }
  6593. /**
  6594. @psalm-return
  6595. */
  6596. private static function getInstalled()
  6597. {
  6598. if (null === self::$canGetVendors) {
  6599. self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
  6600. }
  6601. $installed = array();
  6602. $copiedLocalDir = false;
  6603. if (self::$canGetVendors) {
  6604. $selfDir = self::getSelfDir();
  6605. foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
  6606. $vendorDir = strtr($vendorDir, '\\', '/');
  6607. if (isset(self::$installedByVendor[$vendorDir])) {
  6608. $installed[] = self::$installedByVendor[$vendorDir];
  6609. } elseif (is_file($vendorDir.'/composer/installed.php')) {
  6610. $required = require $vendorDir.'/composer/installed.php';
  6611. self::$installedByVendor[$vendorDir] = $required;
  6612. $installed[] = $required;
  6613. if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
  6614. self::$installed = $required;
  6615. self::$installedIsLocalDir = true;
  6616. }
  6617. }
  6618. if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
  6619. $copiedLocalDir = true;
  6620. }
  6621. }
  6622. }
  6623. if (null === self::$installed) {
  6624. if (substr(__DIR__, -8, 1) !== 'C') {
  6625. $required = require __DIR__ . '/installed.php';
  6626. self::$installed = $required;
  6627. } else {
  6628. self::$installed = array();
  6629. }
  6630. }
  6631. if (self::$installed !== array() && !$copiedLocalDir) {
  6632. $installed[] = self::$installed;
  6633. }
  6634. return $installed;
  6635. }
  6636. }
  6637. <?php return array(
  6638. 'root' => array(
  6639. 'name' => 'friendsofphp/php-cs-fixer',
  6640. 'pretty_version' => 'dev-master',
  6641. 'version' => 'dev-master',
  6642. 'reference' => '97de337e3f3d7524f2f398d31ef9fab643d04692',
  6643. 'type' => 'application',
  6644. 'install_path' => __DIR__ . '/../../',
  6645. 'aliases' => array(),
  6646. 'dev' => false,
  6647. ),
  6648. 'versions' => array(
  6649. 'clue/ndjson-react' => array(
  6650. 'pretty_version' => 'v1.3.0',
  6651. 'version' => '1.3.0.0',
  6652. 'reference' => '392dc165fce93b5bb5c637b67e59619223c931b0',
  6653. 'type' => 'library',
  6654. 'install_path' => __DIR__ . '/../clue/ndjson-react',
  6655. 'aliases' => array(),
  6656. 'dev_requirement' => false,
  6657. ),
  6658. 'composer/pcre' => array(
  6659. 'pretty_version' => '3.3.2',
  6660. 'version' => '3.3.2.0',
  6661. 'reference' => 'b2bed4734f0cc156ee1fe9c0da2550420d99a21e',
  6662. 'type' => 'library',
  6663. 'install_path' => __DIR__ . '/./pcre',
  6664. 'aliases' => array(),
  6665. 'dev_requirement' => false,
  6666. ),
  6667. 'composer/semver' => array(
  6668. 'pretty_version' => '3.4.3',
  6669. 'version' => '3.4.3.0',
  6670. 'reference' => '4313d26ada5e0c4edfbd1dc481a92ff7bff91f12',
  6671. 'type' => 'library',
  6672. 'install_path' => __DIR__ . '/./semver',
  6673. 'aliases' => array(),
  6674. 'dev_requirement' => false,
  6675. ),
  6676. 'composer/xdebug-handler' => array(
  6677. 'pretty_version' => '3.0.5',
  6678. 'version' => '3.0.5.0',
  6679. 'reference' => '6c1925561632e83d60a44492e0b344cf48ab85ef',
  6680. 'type' => 'library',
  6681. 'install_path' => __DIR__ . '/./xdebug-handler',
  6682. 'aliases' => array(),
  6683. 'dev_requirement' => false,
  6684. ),
  6685. 'evenement/evenement' => array(
  6686. 'pretty_version' => 'v3.0.2',
  6687. 'version' => '3.0.2.0',
  6688. 'reference' => '0a16b0d71ab13284339abb99d9d2bd813640efbc',
  6689. 'type' => 'library',
  6690. 'install_path' => __DIR__ . '/../evenement/evenement',
  6691. 'aliases' => array(),
  6692. 'dev_requirement' => false,
  6693. ),
  6694. 'fidry/cpu-core-counter' => array(
  6695. 'pretty_version' => '1.2.0',
  6696. 'version' => '1.2.0.0',
  6697. 'reference' => '8520451a140d3f46ac33042715115e290cf5785f',
  6698. 'type' => 'library',
  6699. 'install_path' => __DIR__ . '/../fidry/cpu-core-counter',
  6700. 'aliases' => array(),
  6701. 'dev_requirement' => false,
  6702. ),
  6703. 'friendsofphp/php-cs-fixer' => array(
  6704. 'pretty_version' => 'dev-master',
  6705. 'version' => 'dev-master',
  6706. 'reference' => '97de337e3f3d7524f2f398d31ef9fab643d04692',
  6707. 'type' => 'application',
  6708. 'install_path' => __DIR__ . '/../../',
  6709. 'aliases' => array(),
  6710. 'dev_requirement' => false,
  6711. ),
  6712. 'psr/container' => array(
  6713. 'pretty_version' => '1.1.2',
  6714. 'version' => '1.1.2.0',
  6715. 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
  6716. 'type' => 'library',
  6717. 'install_path' => __DIR__ . '/../psr/container',
  6718. 'aliases' => array(),
  6719. 'dev_requirement' => false,
  6720. ),
  6721. 'psr/event-dispatcher' => array(
  6722. 'pretty_version' => '1.0.0',
  6723. 'version' => '1.0.0.0',
  6724. 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0',
  6725. 'type' => 'library',
  6726. 'install_path' => __DIR__ . '/../psr/event-dispatcher',
  6727. 'aliases' => array(),
  6728. 'dev_requirement' => false,
  6729. ),
  6730. 'psr/event-dispatcher-implementation' => array(
  6731. 'dev_requirement' => false,
  6732. 'provided' => array(
  6733. 0 => '1.0',
  6734. ),
  6735. ),
  6736. 'psr/log' => array(
  6737. 'pretty_version' => '1.1.4',
  6738. 'version' => '1.1.4.0',
  6739. 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
  6740. 'type' => 'library',
  6741. 'install_path' => __DIR__ . '/../psr/log',
  6742. 'aliases' => array(),
  6743. 'dev_requirement' => false,
  6744. ),
  6745. 'psr/log-implementation' => array(
  6746. 'dev_requirement' => false,
  6747. 'provided' => array(
  6748. 0 => '1.0|2.0',
  6749. ),
  6750. ),
  6751. 'react/cache' => array(
  6752. 'pretty_version' => 'v1.2.0',
  6753. 'version' => '1.2.0.0',
  6754. 'reference' => 'd47c472b64aa5608225f47965a484b75c7817d5b',
  6755. 'type' => 'library',
  6756. 'install_path' => __DIR__ . '/../react/cache',
  6757. 'aliases' => array(),
  6758. 'dev_requirement' => false,
  6759. ),
  6760. 'react/child-process' => array(
  6761. 'pretty_version' => 'v0.6.6',
  6762. 'version' => '0.6.6.0',
  6763. 'reference' => '1721e2b93d89b745664353b9cfc8f155ba8a6159',
  6764. 'type' => 'library',
  6765. 'install_path' => __DIR__ . '/../react/child-process',
  6766. 'aliases' => array(),
  6767. 'dev_requirement' => false,
  6768. ),
  6769. 'react/dns' => array(
  6770. 'pretty_version' => 'v1.13.0',
  6771. 'version' => '1.13.0.0',
  6772. 'reference' => 'eb8ae001b5a455665c89c1df97f6fb682f8fb0f5',
  6773. 'type' => 'library',
  6774. 'install_path' => __DIR__ . '/../react/dns',
  6775. 'aliases' => array(),
  6776. 'dev_requirement' => false,
  6777. ),
  6778. 'react/event-loop' => array(
  6779. 'pretty_version' => 'v1.5.0',
  6780. 'version' => '1.5.0.0',
  6781. 'reference' => 'bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354',
  6782. 'type' => 'library',
  6783. 'install_path' => __DIR__ . '/../react/event-loop',
  6784. 'aliases' => array(),
  6785. 'dev_requirement' => false,
  6786. ),
  6787. 'react/promise' => array(
  6788. 'pretty_version' => 'v3.2.0',
  6789. 'version' => '3.2.0.0',
  6790. 'reference' => '8a164643313c71354582dc850b42b33fa12a4b63',
  6791. 'type' => 'library',
  6792. 'install_path' => __DIR__ . '/../react/promise',
  6793. 'aliases' => array(),
  6794. 'dev_requirement' => false,
  6795. ),
  6796. 'react/socket' => array(
  6797. 'pretty_version' => 'v1.16.0',
  6798. 'version' => '1.16.0.0',
  6799. 'reference' => '23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1',
  6800. 'type' => 'library',
  6801. 'install_path' => __DIR__ . '/../react/socket',
  6802. 'aliases' => array(),
  6803. 'dev_requirement' => false,
  6804. ),
  6805. 'react/stream' => array(
  6806. 'pretty_version' => 'v1.4.0',
  6807. 'version' => '1.4.0.0',
  6808. 'reference' => '1e5b0acb8fe55143b5b426817155190eb6f5b18d',
  6809. 'type' => 'library',
  6810. 'install_path' => __DIR__ . '/../react/stream',
  6811. 'aliases' => array(),
  6812. 'dev_requirement' => false,
  6813. ),
  6814. 'sebastian/diff' => array(
  6815. 'pretty_version' => '4.0.6',
  6816. 'version' => '4.0.6.0',
  6817. 'reference' => 'ba01945089c3a293b01ba9badc29ad55b106b0bc',
  6818. 'type' => 'library',
  6819. 'install_path' => __DIR__ . '/../sebastian/diff',
  6820. 'aliases' => array(),
  6821. 'dev_requirement' => false,
  6822. ),
  6823. 'symfony/console' => array(
  6824. 'pretty_version' => 'v5.4.47',
  6825. 'version' => '5.4.47.0',
  6826. 'reference' => 'c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed',
  6827. 'type' => 'library',
  6828. 'install_path' => __DIR__ . '/../symfony/console',
  6829. 'aliases' => array(),
  6830. 'dev_requirement' => false,
  6831. ),
  6832. 'symfony/deprecation-contracts' => array(
  6833. 'pretty_version' => 'v2.5.4',
  6834. 'version' => '2.5.4.0',
  6835. 'reference' => '605389f2a7e5625f273b53960dc46aeaf9c62918',
  6836. 'type' => 'library',
  6837. 'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
  6838. 'aliases' => array(),
  6839. 'dev_requirement' => false,
  6840. ),
  6841. 'symfony/event-dispatcher' => array(
  6842. 'pretty_version' => 'v5.4.45',
  6843. 'version' => '5.4.45.0',
  6844. 'reference' => '72982eb416f61003e9bb6e91f8b3213600dcf9e9',
  6845. 'type' => 'library',
  6846. 'install_path' => __DIR__ . '/../symfony/event-dispatcher',
  6847. 'aliases' => array(),
  6848. 'dev_requirement' => false,
  6849. ),
  6850. 'symfony/event-dispatcher-contracts' => array(
  6851. 'pretty_version' => 'v2.5.4',
  6852. 'version' => '2.5.4.0',
  6853. 'reference' => 'e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f',
  6854. 'type' => 'library',
  6855. 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
  6856. 'aliases' => array(),
  6857. 'dev_requirement' => false,
  6858. ),
  6859. 'symfony/event-dispatcher-implementation' => array(
  6860. 'dev_requirement' => false,
  6861. 'provided' => array(
  6862. 0 => '2.0',
  6863. ),
  6864. ),
  6865. 'symfony/filesystem' => array(
  6866. 'pretty_version' => 'v5.4.45',
  6867. 'version' => '5.4.45.0',
  6868. 'reference' => '57c8294ed37d4a055b77057827c67f9558c95c54',
  6869. 'type' => 'library',
  6870. 'install_path' => __DIR__ . '/../symfony/filesystem',
  6871. 'aliases' => array(),
  6872. 'dev_requirement' => false,
  6873. ),
  6874. 'symfony/finder' => array(
  6875. 'pretty_version' => 'v5.4.45',
  6876. 'version' => '5.4.45.0',
  6877. 'reference' => '63741784cd7b9967975eec610b256eed3ede022b',
  6878. 'type' => 'library',
  6879. 'install_path' => __DIR__ . '/../symfony/finder',
  6880. 'aliases' => array(),
  6881. 'dev_requirement' => false,
  6882. ),
  6883. 'symfony/options-resolver' => array(
  6884. 'pretty_version' => 'v5.4.45',
  6885. 'version' => '5.4.45.0',
  6886. 'reference' => '74e5b6f0db3e8589e6cfd5efb317a1fc2bb52fb6',
  6887. 'type' => 'library',
  6888. 'install_path' => __DIR__ . '/../symfony/options-resolver',
  6889. 'aliases' => array(),
  6890. 'dev_requirement' => false,
  6891. ),
  6892. 'symfony/polyfill-ctype' => array(
  6893. 'pretty_version' => 'v1.32.0',
  6894. 'version' => '1.32.0.0',
  6895. 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
  6896. 'type' => 'library',
  6897. 'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
  6898. 'aliases' => array(),
  6899. 'dev_requirement' => false,
  6900. ),
  6901. 'symfony/polyfill-intl-grapheme' => array(
  6902. 'pretty_version' => 'v1.32.0',
  6903. 'version' => '1.32.0.0',
  6904. 'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe',
  6905. 'type' => 'library',
  6906. 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
  6907. 'aliases' => array(),
  6908. 'dev_requirement' => false,
  6909. ),
  6910. 'symfony/polyfill-intl-normalizer' => array(
  6911. 'pretty_version' => 'v1.32.0',
  6912. 'version' => '1.32.0.0',
  6913. 'reference' => '3833d7255cc303546435cb650316bff708a1c75c',
  6914. 'type' => 'library',
  6915. 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
  6916. 'aliases' => array(),
  6917. 'dev_requirement' => false,
  6918. ),
  6919. 'symfony/polyfill-mbstring' => array(
  6920. 'pretty_version' => 'v1.32.0',
  6921. 'version' => '1.32.0.0',
  6922. 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
  6923. 'type' => 'library',
  6924. 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
  6925. 'aliases' => array(),
  6926. 'dev_requirement' => false,
  6927. ),
  6928. 'symfony/polyfill-php73' => array(
  6929. 'pretty_version' => 'v1.32.0',
  6930. 'version' => '1.32.0.0',
  6931. 'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb',
  6932. 'type' => 'library',
  6933. 'install_path' => __DIR__ . '/../symfony/polyfill-php73',
  6934. 'aliases' => array(),
  6935. 'dev_requirement' => false,
  6936. ),
  6937. 'symfony/polyfill-php80' => array(
  6938. 'pretty_version' => 'v1.32.0',
  6939. 'version' => '1.32.0.0',
  6940. 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',
  6941. 'type' => 'library',
  6942. 'install_path' => __DIR__ . '/../symfony/polyfill-php80',
  6943. 'aliases' => array(),
  6944. 'dev_requirement' => false,
  6945. ),
  6946. 'symfony/polyfill-php81' => array(
  6947. 'pretty_version' => 'v1.32.0',
  6948. 'version' => '1.32.0.0',
  6949. 'reference' => '4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c',
  6950. 'type' => 'library',
  6951. 'install_path' => __DIR__ . '/../symfony/polyfill-php81',
  6952. 'aliases' => array(),
  6953. 'dev_requirement' => false,
  6954. ),
  6955. 'symfony/process' => array(
  6956. 'pretty_version' => 'v5.4.47',
  6957. 'version' => '5.4.47.0',
  6958. 'reference' => '5d1662fb32ebc94f17ddb8d635454a776066733d',
  6959. 'type' => 'library',
  6960. 'install_path' => __DIR__ . '/../symfony/process',
  6961. 'aliases' => array(),
  6962. 'dev_requirement' => false,
  6963. ),
  6964. 'symfony/service-contracts' => array(
  6965. 'pretty_version' => 'v2.5.4',
  6966. 'version' => '2.5.4.0',
  6967. 'reference' => 'f37b419f7aea2e9abf10abd261832cace12e3300',
  6968. 'type' => 'library',
  6969. 'install_path' => __DIR__ . '/../symfony/service-contracts',
  6970. 'aliases' => array(),
  6971. 'dev_requirement' => false,
  6972. ),
  6973. 'symfony/stopwatch' => array(
  6974. 'pretty_version' => 'v5.4.45',
  6975. 'version' => '5.4.45.0',
  6976. 'reference' => 'fb2c199cf302eb207f8c23e7ee174c1c31a5c004',
  6977. 'type' => 'library',
  6978. 'install_path' => __DIR__ . '/../symfony/stopwatch',
  6979. 'aliases' => array(),
  6980. 'dev_requirement' => false,
  6981. ),
  6982. 'symfony/string' => array(
  6983. 'pretty_version' => 'v5.4.47',
  6984. 'version' => '5.4.47.0',
  6985. 'reference' => '136ca7d72f72b599f2631aca474a4f8e26719799',
  6986. 'type' => 'library',
  6987. 'install_path' => __DIR__ . '/../symfony/string',
  6988. 'aliases' => array(),
  6989. 'dev_requirement' => false,
  6990. ),
  6991. ),
  6992. );
  6993. <?php declare(strict_types=1);
  6994. namespace Composer\Pcre\PHPStan;
  6995. use Composer\Pcre\Preg;
  6996. use PhpParser\Node\Expr\StaticCall;
  6997. use PHPStan\Analyser\Scope;
  6998. use PHPStan\Analyser\SpecifiedTypes;
  6999. use PHPStan\Analyser\TypeSpecifier;
  7000. use PHPStan\Analyser\TypeSpecifierAwareExtension;
  7001. use PHPStan\Analyser\TypeSpecifierContext;
  7002. use PHPStan\Reflection\MethodReflection;
  7003. use PHPStan\TrinaryLogic;
  7004. use PHPStan\Type\Constant\ConstantArrayType;
  7005. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  7006. use PHPStan\Type\StaticMethodTypeSpecifyingExtension;
  7007. use PHPStan\Type\TypeCombinator;
  7008. use PHPStan\Type\Type;
  7009. final class PregMatchTypeSpecifyingExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
  7010. {
  7011. private $typeSpecifier;
  7012. private $regexShapeMatcher;
  7013. public function __construct(RegexArrayShapeMatcher $regexShapeMatcher)
  7014. {
  7015. $this->regexShapeMatcher = $regexShapeMatcher;
  7016. }
  7017. public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
  7018. {
  7019. $this->typeSpecifier = $typeSpecifier;
  7020. }
  7021. public function getClass(): string
  7022. {
  7023. return Preg::class;
  7024. }
  7025. public function isStaticMethodSupported(MethodReflection $methodReflection, StaticCall $node, TypeSpecifierContext $context): bool
  7026. {
  7027. return in_array($methodReflection->getName(), [
  7028. 'match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups',
  7029. 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups'
  7030. ], true)
  7031. && !$context->null();
  7032. }
  7033. public function specifyTypes(MethodReflection $methodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
  7034. {
  7035. $args = $node->getArgs();
  7036. $patternArg = $args[0] ?? null;
  7037. $matchesArg = $args[2] ?? null;
  7038. $flagsArg = $args[3] ?? null;
  7039. if (
  7040. $patternArg === null || $matchesArg === null
  7041. ) {
  7042. return new SpecifiedTypes();
  7043. }
  7044. $flagsType = PregMatchFlags::getType($flagsArg, $scope);
  7045. if ($flagsType === null) {
  7046. return new SpecifiedTypes();
  7047. }
  7048. if (stripos($methodReflection->getName(), 'matchAll') !== false) {
  7049. $matchedType = $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope);
  7050. } else {
  7051. $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope);
  7052. }
  7053. if ($matchedType === null) {
  7054. return new SpecifiedTypes();
  7055. }
  7056. if (
  7057. in_array($methodReflection->getName(), ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], true)
  7058. ) {
  7059. $matchedType = PregMatchFlags::removeNullFromMatches($matchedType);
  7060. }
  7061. $overwrite = false;
  7062. if ($context->false()) {
  7063. $overwrite = true;
  7064. $context = $context->negate();
  7065. }
  7066. if (method_exists('PHPStan\Analyser\SpecifiedTypes', 'setRootExpr')) {
  7067. $typeSpecifier = $this->typeSpecifier->create(
  7068. $matchesArg->value,
  7069. $matchedType,
  7070. $context,
  7071. $scope
  7072. )->setRootExpr($node);
  7073. return $overwrite ? $typeSpecifier->setAlwaysOverwriteTypes() : $typeSpecifier;
  7074. }
  7075. return $this->typeSpecifier->create(
  7076. $matchesArg->value,
  7077. $matchedType,
  7078. $context,
  7079. $overwrite,
  7080. $scope,
  7081. $node
  7082. );
  7083. }
  7084. }
  7085. <?php declare(strict_types=1);
  7086. namespace Composer\Pcre\PHPStan;
  7087. use Composer\Pcre\Preg;
  7088. use Composer\Pcre\Regex;
  7089. use PhpParser\Node\Expr\StaticCall;
  7090. use PHPStan\Analyser\Scope;
  7091. use PHPStan\Reflection\MethodReflection;
  7092. use PHPStan\Reflection\Native\NativeParameterReflection;
  7093. use PHPStan\Reflection\ParameterReflection;
  7094. use PHPStan\TrinaryLogic;
  7095. use PHPStan\Type\ClosureType;
  7096. use PHPStan\Type\Constant\ConstantArrayType;
  7097. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  7098. use PHPStan\Type\StaticMethodParameterClosureTypeExtension;
  7099. use PHPStan\Type\StringType;
  7100. use PHPStan\Type\TypeCombinator;
  7101. use PHPStan\Type\Type;
  7102. final class PregReplaceCallbackClosureTypeExtension implements StaticMethodParameterClosureTypeExtension
  7103. {
  7104. private $regexShapeMatcher;
  7105. public function __construct(RegexArrayShapeMatcher $regexShapeMatcher)
  7106. {
  7107. $this->regexShapeMatcher = $regexShapeMatcher;
  7108. }
  7109. public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter): bool
  7110. {
  7111. return in_array($methodReflection->getDeclaringClass()->getName(), [Preg::class, Regex::class], true)
  7112. && in_array($methodReflection->getName(), ['replaceCallback', 'replaceCallbackStrictGroups'], true)
  7113. && $parameter->getName() === 'replacement';
  7114. }
  7115. public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope): ?Type
  7116. {
  7117. $args = $methodCall->getArgs();
  7118. $patternArg = $args[0] ?? null;
  7119. $flagsArg = $args[5] ?? null;
  7120. if (
  7121. $patternArg === null
  7122. ) {
  7123. return null;
  7124. }
  7125. $flagsType = PregMatchFlags::getType($flagsArg, $scope);
  7126. $matchesType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope);
  7127. if ($matchesType === null) {
  7128. return null;
  7129. }
  7130. if ($methodReflection->getName() === 'replaceCallbackStrictGroups' && count($matchesType->getConstantArrays()) === 1) {
  7131. $matchesType = $matchesType->getConstantArrays()[0];
  7132. $matchesType = new ConstantArrayType(
  7133. $matchesType->getKeyTypes(),
  7134. array_map(static function (Type $valueType): Type {
  7135. if (count($valueType->getConstantArrays()) === 1) {
  7136. $valueTypeArray = $valueType->getConstantArrays()[0];
  7137. return new ConstantArrayType(
  7138. $valueTypeArray->getKeyTypes(),
  7139. array_map(static function (Type $valueType): Type {
  7140. return TypeCombinator::removeNull($valueType);
  7141. }, $valueTypeArray->getValueTypes()),
  7142. $valueTypeArray->getNextAutoIndexes(),
  7143. [],
  7144. $valueTypeArray->isList()
  7145. );
  7146. }
  7147. return TypeCombinator::removeNull($valueType);
  7148. }, $matchesType->getValueTypes()),
  7149. $matchesType->getNextAutoIndexes(),
  7150. [],
  7151. $matchesType->isList()
  7152. );
  7153. }
  7154. return new ClosureType(
  7155. [
  7156. new NativeParameterReflection($parameter->getName(), $parameter->isOptional(), $matchesType, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue()),
  7157. ],
  7158. new StringType()
  7159. );
  7160. }
  7161. }
  7162. <?php declare(strict_types=1);
  7163. namespace Composer\Pcre\PHPStan;
  7164. use Composer\Pcre\Preg;
  7165. use PhpParser\Node\Expr\StaticCall;
  7166. use PHPStan\Analyser\Scope;
  7167. use PHPStan\Reflection\MethodReflection;
  7168. use PHPStan\Reflection\ParameterReflection;
  7169. use PHPStan\TrinaryLogic;
  7170. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  7171. use PHPStan\Type\StaticMethodParameterOutTypeExtension;
  7172. use PHPStan\Type\Type;
  7173. final class PregMatchParameterOutTypeExtension implements StaticMethodParameterOutTypeExtension
  7174. {
  7175. private $regexShapeMatcher;
  7176. public function __construct(
  7177. RegexArrayShapeMatcher $regexShapeMatcher
  7178. )
  7179. {
  7180. $this->regexShapeMatcher = $regexShapeMatcher;
  7181. }
  7182. public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter): bool
  7183. {
  7184. return
  7185. $methodReflection->getDeclaringClass()->getName() === Preg::class
  7186. && in_array($methodReflection->getName(), [
  7187. 'match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups',
  7188. 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups'
  7189. ], true)
  7190. && $parameter->getName() === 'matches';
  7191. }
  7192. public function getParameterOutTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope): ?Type
  7193. {
  7194. $args = $methodCall->getArgs();
  7195. $patternArg = $args[0] ?? null;
  7196. $matchesArg = $args[2] ?? null;
  7197. $flagsArg = $args[3] ?? null;
  7198. if (
  7199. $patternArg === null || $matchesArg === null
  7200. ) {
  7201. return null;
  7202. }
  7203. $flagsType = PregMatchFlags::getType($flagsArg, $scope);
  7204. if ($flagsType === null) {
  7205. return null;
  7206. }
  7207. if (stripos($methodReflection->getName(), 'matchAll') !== false) {
  7208. return $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope);
  7209. }
  7210. return $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope);
  7211. }
  7212. }
  7213. <?php declare(strict_types = 1);
  7214. namespace Composer\Pcre\PHPStan;
  7215. use Composer\Pcre\Preg;
  7216. use Composer\Pcre\Regex;
  7217. use Composer\Pcre\PcreException;
  7218. use Nette\Utils\RegexpException;
  7219. use Nette\Utils\Strings;
  7220. use PhpParser\Node;
  7221. use PhpParser\Node\Expr\StaticCall;
  7222. use PhpParser\Node\Name\FullyQualified;
  7223. use PHPStan\Analyser\Scope;
  7224. use PHPStan\Rules\Rule;
  7225. use PHPStan\Rules\RuleErrorBuilder;
  7226. use function in_array;
  7227. use function sprintf;
  7228. /**
  7229. @implements
  7230. */
  7231. class InvalidRegexPatternRule implements Rule
  7232. {
  7233. public function getNodeType(): string
  7234. {
  7235. return StaticCall::class;
  7236. }
  7237. public function processNode(Node $node, Scope $scope): array
  7238. {
  7239. $patterns = $this->extractPatterns($node, $scope);
  7240. $errors = [];
  7241. foreach ($patterns as $pattern) {
  7242. $errorMessage = $this->validatePattern($pattern);
  7243. if ($errorMessage === null) {
  7244. continue;
  7245. }
  7246. $errors[] = RuleErrorBuilder::message(sprintf('Regex pattern is invalid: %s', $errorMessage))->identifier('regexp.pattern')->build();
  7247. }
  7248. return $errors;
  7249. }
  7250. private function extractPatterns(StaticCall $node, Scope $scope): array
  7251. {
  7252. if (!$node->class instanceof FullyQualified) {
  7253. return [];
  7254. }
  7255. $isRegex = $node->class->toString() === Regex::class;
  7256. $isPreg = $node->class->toString() === Preg::class;
  7257. if (!$isRegex && !$isPreg) {
  7258. return [];
  7259. }
  7260. if (!$node->name instanceof Node\Identifier || !Preg::isMatch('{^(match|isMatch|grep|replace|split)}', $node->name->name)) {
  7261. return [];
  7262. }
  7263. $functionName = $node->name->name;
  7264. if (!isset($node->getArgs()[0])) {
  7265. return [];
  7266. }
  7267. $patternNode = $node->getArgs()[0]->value;
  7268. $patternType = $scope->getType($patternNode);
  7269. $patternStrings = [];
  7270. foreach ($patternType->getConstantStrings() as $constantStringType) {
  7271. if ($functionName === 'replaceCallbackArray') {
  7272. continue;
  7273. }
  7274. $patternStrings[] = $constantStringType->getValue();
  7275. }
  7276. foreach ($patternType->getConstantArrays() as $constantArrayType) {
  7277. if (
  7278. in_array($functionName, [
  7279. 'replace',
  7280. 'replaceCallback',
  7281. ], true)
  7282. ) {
  7283. foreach ($constantArrayType->getValueTypes() as $arrayKeyType) {
  7284. foreach ($arrayKeyType->getConstantStrings() as $constantString) {
  7285. $patternStrings[] = $constantString->getValue();
  7286. }
  7287. }
  7288. }
  7289. if ($functionName !== 'replaceCallbackArray') {
  7290. continue;
  7291. }
  7292. foreach ($constantArrayType->getKeyTypes() as $arrayKeyType) {
  7293. foreach ($arrayKeyType->getConstantStrings() as $constantString) {
  7294. $patternStrings[] = $constantString->getValue();
  7295. }
  7296. }
  7297. }
  7298. return $patternStrings;
  7299. }
  7300. private function validatePattern(string $pattern): ?string
  7301. {
  7302. try {
  7303. $msg = null;
  7304. $prev = set_error_handler(function (int $severity, string $message, string $file) use (&$msg): bool {
  7305. $msg = preg_replace("#^preg_match(_all)?\\(.*?\\): #", '', $message);
  7306. return true;
  7307. });
  7308. if ($pattern === '') {
  7309. return 'Empty string is not a valid regular expression';
  7310. }
  7311. Preg::match($pattern, '');
  7312. if ($msg !== null) {
  7313. return $msg;
  7314. }
  7315. } catch (PcreException $e) {
  7316. if ($e->getCode() === PREG_INTERNAL_ERROR && $msg !== null) {
  7317. return $msg;
  7318. }
  7319. return preg_replace('{.*? failed executing ".*": }', '', $e->getMessage());
  7320. } finally {
  7321. restore_error_handler();
  7322. }
  7323. return null;
  7324. }
  7325. }
  7326. <?php declare(strict_types=1);
  7327. namespace Composer\Pcre\PHPStan;
  7328. use PHPStan\Analyser\Scope;
  7329. use PHPStan\Type\ArrayType;
  7330. use PHPStan\Type\Constant\ConstantArrayType;
  7331. use PHPStan\Type\Constant\ConstantIntegerType;
  7332. use PHPStan\Type\IntersectionType;
  7333. use PHPStan\Type\TypeCombinator;
  7334. use PHPStan\Type\Type;
  7335. use PhpParser\Node\Arg;
  7336. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  7337. use PHPStan\Type\TypeTraverser;
  7338. use PHPStan\Type\UnionType;
  7339. final class PregMatchFlags
  7340. {
  7341. static public function getType(?Arg $flagsArg, Scope $scope): ?Type
  7342. {
  7343. if ($flagsArg === null) {
  7344. return new ConstantIntegerType(PREG_UNMATCHED_AS_NULL);
  7345. }
  7346. $flagsType = $scope->getType($flagsArg->value);
  7347. $constantScalars = $flagsType->getConstantScalarValues();
  7348. if ($constantScalars === []) {
  7349. return null;
  7350. }
  7351. $internalFlagsTypes = [];
  7352. foreach ($flagsType->getConstantScalarValues() as $constantScalarValue) {
  7353. if (!is_int($constantScalarValue)) {
  7354. return null;
  7355. }
  7356. $internalFlagsTypes[] = new ConstantIntegerType($constantScalarValue | PREG_UNMATCHED_AS_NULL);
  7357. }
  7358. return TypeCombinator::union(...$internalFlagsTypes);
  7359. }
  7360. static public function removeNullFromMatches(Type $matchesType): Type
  7361. {
  7362. return TypeTraverser::map($matchesType, static function (Type $type, callable $traverse): Type {
  7363. if ($type instanceof UnionType || $type instanceof IntersectionType) {
  7364. return $traverse($type);
  7365. }
  7366. if ($type instanceof ConstantArrayType) {
  7367. return new ConstantArrayType(
  7368. $type->getKeyTypes(),
  7369. array_map(static function (Type $valueType) use ($traverse): Type {
  7370. return $traverse($valueType);
  7371. }, $type->getValueTypes()),
  7372. $type->getNextAutoIndexes(),
  7373. [],
  7374. $type->isList()
  7375. );
  7376. }
  7377. if ($type instanceof ArrayType) {
  7378. return new ArrayType($type->getKeyType(), $traverse($type->getItemType()));
  7379. }
  7380. return TypeCombinator::removeNull($type);
  7381. });
  7382. }
  7383. }
  7384. <?php declare(strict_types=1);
  7385. namespace Composer\Pcre\PHPStan;
  7386. use Composer\Pcre\Preg;
  7387. use Composer\Pcre\Regex;
  7388. use PhpParser\Node;
  7389. use PhpParser\Node\Expr\StaticCall;
  7390. use PhpParser\Node\Name\FullyQualified;
  7391. use PHPStan\Analyser\Scope;
  7392. use PHPStan\Analyser\SpecifiedTypes;
  7393. use PHPStan\Rules\Rule;
  7394. use PHPStan\Rules\RuleErrorBuilder;
  7395. use PHPStan\TrinaryLogic;
  7396. use PHPStan\Type\ObjectType;
  7397. use PHPStan\Type\Type;
  7398. use PHPStan\Type\TypeCombinator;
  7399. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  7400. use function sprintf;
  7401. /**
  7402. @implements
  7403. */
  7404. final class UnsafeStrictGroupsCallRule implements Rule
  7405. {
  7406. private $regexShapeMatcher;
  7407. public function __construct(RegexArrayShapeMatcher $regexShapeMatcher)
  7408. {
  7409. $this->regexShapeMatcher = $regexShapeMatcher;
  7410. }
  7411. public function getNodeType(): string
  7412. {
  7413. return StaticCall::class;
  7414. }
  7415. public function processNode(Node $node, Scope $scope): array
  7416. {
  7417. if (!$node->class instanceof FullyQualified) {
  7418. return [];
  7419. }
  7420. $isRegex = $node->class->toString() === Regex::class;
  7421. $isPreg = $node->class->toString() === Preg::class;
  7422. if (!$isRegex && !$isPreg) {
  7423. return [];
  7424. }
  7425. if (!$node->name instanceof Node\Identifier || !in_array($node->name->name, ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], true)) {
  7426. return [];
  7427. }
  7428. $args = $node->getArgs();
  7429. if (!isset($args[0])) {
  7430. return [];
  7431. }
  7432. $patternArg = $args[0] ?? null;
  7433. if ($isPreg) {
  7434. if (!isset($args[2])) {
  7435. return [];
  7436. }
  7437. $flagsArg = $args[3] ?? null;
  7438. } else {
  7439. $flagsArg = $args[2] ?? null;
  7440. }
  7441. if ($patternArg === null) {
  7442. return [];
  7443. }
  7444. $flagsType = PregMatchFlags::getType($flagsArg, $scope);
  7445. if ($flagsType === null) {
  7446. return [];
  7447. }
  7448. $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope);
  7449. if ($matchedType === null) {
  7450. return [
  7451. RuleErrorBuilder::message(sprintf('The %s call is potentially unsafe as $matches\' type could not be inferred.', $node->name->name))
  7452. ->identifier('composerPcre.maybeUnsafeStrictGroups')
  7453. ->build(),
  7454. ];
  7455. }
  7456. if (count($matchedType->getConstantArrays()) === 1) {
  7457. $matchedType = $matchedType->getConstantArrays()[0];
  7458. $nullableGroups = [];
  7459. foreach ($matchedType->getValueTypes() as $index => $type) {
  7460. if (TypeCombinator::containsNull($type)) {
  7461. $nullableGroups[] = $matchedType->getKeyTypes()[$index]->getValue();
  7462. }
  7463. }
  7464. if (\count($nullableGroups) > 0) {
  7465. return [
  7466. RuleErrorBuilder::message(sprintf(
  7467. 'The %s call is unsafe as match group%s "%s" %s optional and may be null.',
  7468. $node->name->name,
  7469. \count($nullableGroups) > 1 ? 's' : '',
  7470. implode('", "', $nullableGroups),
  7471. \count($nullableGroups) > 1 ? 'are' : 'is'
  7472. ))->identifier('composerPcre.unsafeStrictGroups')->build(),
  7473. ];
  7474. }
  7475. }
  7476. return [];
  7477. }
  7478. }
  7479. <?php
  7480. namespace Composer\Pcre;
  7481. final class MatchResult
  7482. {
  7483. /**
  7484. @readonly
  7485. */
  7486. public $matches;
  7487. /**
  7488. @readonly
  7489. */
  7490. public $matched;
  7491. public function __construct(int $count, array $matches)
  7492. {
  7493. $this->matches = $matches;
  7494. $this->matched = (bool) $count;
  7495. }
  7496. }
  7497. <?php
  7498. namespace Composer\Pcre;
  7499. class Regex
  7500. {
  7501. public static function isMatch(string $pattern, string $subject, int $offset = 0): bool
  7502. {
  7503. return (bool) Preg::match($pattern, $subject, $matches, 0, $offset);
  7504. }
  7505. public static function match(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchResult
  7506. {
  7507. self::checkOffsetCapture($flags, 'matchWithOffsets');
  7508. $count = Preg::match($pattern, $subject, $matches, $flags, $offset);
  7509. return new MatchResult($count, $matches);
  7510. }
  7511. public static function matchStrictGroups(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchStrictGroupsResult
  7512. {
  7513. $count = Preg::matchStrictGroups($pattern, $subject, $matches, $flags, $offset);
  7514. return new MatchStrictGroupsResult($count, $matches);
  7515. }
  7516. public static function matchWithOffsets(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchWithOffsetsResult
  7517. {
  7518. $count = Preg::matchWithOffsets($pattern, $subject, $matches, $flags, $offset);
  7519. return new MatchWithOffsetsResult($count, $matches);
  7520. }
  7521. public static function matchAll(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchAllResult
  7522. {
  7523. self::checkOffsetCapture($flags, 'matchAllWithOffsets');
  7524. self::checkSetOrder($flags);
  7525. $count = Preg::matchAll($pattern, $subject, $matches, $flags, $offset);
  7526. return new MatchAllResult($count, $matches);
  7527. }
  7528. public static function matchAllStrictGroups(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchAllStrictGroupsResult
  7529. {
  7530. self::checkOffsetCapture($flags, 'matchAllWithOffsets');
  7531. self::checkSetOrder($flags);
  7532. $count = Preg::matchAllStrictGroups($pattern, $subject, $matches, $flags, $offset);
  7533. return new MatchAllStrictGroupsResult($count, $matches);
  7534. }
  7535. public static function matchAllWithOffsets(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchAllWithOffsetsResult
  7536. {
  7537. self::checkSetOrder($flags);
  7538. $count = Preg::matchAllWithOffsets($pattern, $subject, $matches, $flags, $offset);
  7539. return new MatchAllWithOffsetsResult($count, $matches);
  7540. }
  7541. public static function replace($pattern, $replacement, $subject, int $limit = -1): ReplaceResult
  7542. {
  7543. $result = Preg::replace($pattern, $replacement, $subject, $limit, $count);
  7544. return new ReplaceResult($count, $result);
  7545. }
  7546. public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, int $flags = 0): ReplaceResult
  7547. {
  7548. $result = Preg::replaceCallback($pattern, $replacement, $subject, $limit, $count, $flags);
  7549. return new ReplaceResult($count, $result);
  7550. }
  7551. public static function replaceCallbackStrictGroups($pattern, callable $replacement, $subject, int $limit = -1, int $flags = 0): ReplaceResult
  7552. {
  7553. $result = Preg::replaceCallbackStrictGroups($pattern, $replacement, $subject, $limit, $count, $flags);
  7554. return new ReplaceResult($count, $result);
  7555. }
  7556. public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, int $flags = 0): ReplaceResult
  7557. {
  7558. $result = Preg::replaceCallbackArray($pattern, $subject, $limit, $count, $flags);
  7559. return new ReplaceResult($count, $result);
  7560. }
  7561. private static function checkOffsetCapture(int $flags, string $useFunctionName): void
  7562. {
  7563. if (($flags & PREG_OFFSET_CAPTURE) !== 0) {
  7564. throw new \InvalidArgumentException('PREG_OFFSET_CAPTURE is not supported as it changes the return type, use '.$useFunctionName.'() instead');
  7565. }
  7566. }
  7567. private static function checkSetOrder(int $flags): void
  7568. {
  7569. if (($flags & PREG_SET_ORDER) !== 0) {
  7570. throw new \InvalidArgumentException('PREG_SET_ORDER is not supported as it changes the return type');
  7571. }
  7572. }
  7573. }
  7574. <?php
  7575. namespace Composer\Pcre;
  7576. final class MatchAllWithOffsetsResult
  7577. {
  7578. /**
  7579. @readonly
  7580. @phpstan-var
  7581. */
  7582. public $matches;
  7583. /**
  7584. @readonly
  7585. */
  7586. public $count;
  7587. /**
  7588. @readonly
  7589. */
  7590. public $matched;
  7591. /**
  7592. @phpstan-param
  7593. */
  7594. public function __construct(int $count, array $matches)
  7595. {
  7596. $this->matches = $matches;
  7597. $this->matched = (bool) $count;
  7598. $this->count = $count;
  7599. }
  7600. }
  7601. <?php
  7602. namespace Composer\Pcre;
  7603. final class MatchWithOffsetsResult
  7604. {
  7605. /**
  7606. @readonly
  7607. @phpstan-var
  7608. */
  7609. public $matches;
  7610. /**
  7611. @readonly
  7612. */
  7613. public $matched;
  7614. /**
  7615. @phpstan-param
  7616. */
  7617. public function __construct(int $count, array $matches)
  7618. {
  7619. $this->matches = $matches;
  7620. $this->matched = (bool) $count;
  7621. }
  7622. }
  7623. <?php
  7624. namespace Composer\Pcre;
  7625. final class MatchAllStrictGroupsResult
  7626. {
  7627. /**
  7628. @readonly
  7629. */
  7630. public $matches;
  7631. /**
  7632. @readonly
  7633. */
  7634. public $count;
  7635. /**
  7636. @readonly
  7637. */
  7638. public $matched;
  7639. public function __construct(int $count, array $matches)
  7640. {
  7641. $this->matches = $matches;
  7642. $this->matched = (bool) $count;
  7643. $this->count = $count;
  7644. }
  7645. }
  7646. <?php
  7647. namespace Composer\Pcre;
  7648. class UnexpectedNullMatchException extends PcreException
  7649. {
  7650. public static function fromFunction($function, $pattern)
  7651. {
  7652. throw new \LogicException('fromFunction should not be called on '.self::class.', use '.PcreException::class);
  7653. }
  7654. }
  7655. <?php
  7656. namespace Composer\Pcre;
  7657. final class MatchStrictGroupsResult
  7658. {
  7659. /**
  7660. @readonly
  7661. */
  7662. public $matches;
  7663. /**
  7664. @readonly
  7665. */
  7666. public $matched;
  7667. public function __construct(int $count, array $matches)
  7668. {
  7669. $this->matches = $matches;
  7670. $this->matched = (bool) $count;
  7671. }
  7672. }
  7673. <?php
  7674. namespace Composer\Pcre;
  7675. final class MatchAllResult
  7676. {
  7677. /**
  7678. @readonly
  7679. */
  7680. public $matches;
  7681. /**
  7682. @readonly
  7683. */
  7684. public $count;
  7685. /**
  7686. @readonly
  7687. */
  7688. public $matched;
  7689. public function __construct(int $count, array $matches)
  7690. {
  7691. $this->matches = $matches;
  7692. $this->matched = (bool) $count;
  7693. $this->count = $count;
  7694. }
  7695. }
  7696. <?php
  7697. namespace Composer\Pcre;
  7698. final class ReplaceResult
  7699. {
  7700. /**
  7701. @readonly
  7702. */
  7703. public $result;
  7704. /**
  7705. @readonly
  7706. */
  7707. public $count;
  7708. /**
  7709. @readonly
  7710. */
  7711. public $matched;
  7712. public function __construct(int $count, string $result)
  7713. {
  7714. $this->count = $count;
  7715. $this->matched = (bool) $count;
  7716. $this->result = $result;
  7717. }
  7718. }
  7719. <?php
  7720. namespace Composer\Pcre;
  7721. class Preg
  7722. {
  7723. public const ARRAY_MSG = '$subject as an array is not supported. You can use \'foreach\' instead.';
  7724. public const INVALID_TYPE_MSG = '$subject must be a string, %s given.';
  7725. /**
  7726. @param-out
  7727. */
  7728. public static function match(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int
  7729. {
  7730. self::checkOffsetCapture($flags, 'matchWithOffsets');
  7731. $result = preg_match($pattern, $subject, $matches, $flags | PREG_UNMATCHED_AS_NULL, $offset);
  7732. if ($result === false) {
  7733. throw PcreException::fromFunction('preg_match', $pattern);
  7734. }
  7735. return $result;
  7736. }
  7737. /**
  7738. @param-out
  7739. */
  7740. public static function matchStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int
  7741. {
  7742. $result = self::match($pattern, $subject, $matchesInternal, $flags, $offset);
  7743. $matches = self::enforceNonNullMatches($pattern, $matchesInternal, 'match');
  7744. return $result;
  7745. }
  7746. /**
  7747. @param-out
  7748. */
  7749. public static function matchWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0): int
  7750. {
  7751. $result = preg_match($pattern, $subject, $matches, $flags | PREG_UNMATCHED_AS_NULL | PREG_OFFSET_CAPTURE, $offset);
  7752. if ($result === false) {
  7753. throw PcreException::fromFunction('preg_match', $pattern);
  7754. }
  7755. return $result;
  7756. }
  7757. /**
  7758. @param-out
  7759. */
  7760. public static function matchAll(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int
  7761. {
  7762. self::checkOffsetCapture($flags, 'matchAllWithOffsets');
  7763. self::checkSetOrder($flags);
  7764. $result = preg_match_all($pattern, $subject, $matches, $flags | PREG_UNMATCHED_AS_NULL, $offset);
  7765. if (!is_int($result)) {
  7766. throw PcreException::fromFunction('preg_match_all', $pattern);
  7767. }
  7768. return $result;
  7769. }
  7770. /**
  7771. @param-out
  7772. */
  7773. public static function matchAllStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int
  7774. {
  7775. $result = self::matchAll($pattern, $subject, $matchesInternal, $flags, $offset);
  7776. $matches = self::enforceNonNullMatchAll($pattern, $matchesInternal, 'matchAll');
  7777. return $result;
  7778. }
  7779. /**
  7780. @param-out
  7781. */
  7782. public static function matchAllWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0): int
  7783. {
  7784. self::checkSetOrder($flags);
  7785. $result = preg_match_all($pattern, $subject, $matches, $flags | PREG_UNMATCHED_AS_NULL | PREG_OFFSET_CAPTURE, $offset);
  7786. if (!is_int($result)) {
  7787. throw PcreException::fromFunction('preg_match_all', $pattern);
  7788. }
  7789. return $result;
  7790. }
  7791. /**
  7792. @param-out
  7793. */
  7794. public static function replace($pattern, $replacement, $subject, int $limit = -1, ?int &$count = null): string
  7795. {
  7796. if (!is_scalar($subject)) {
  7797. if (is_array($subject)) {
  7798. throw new \InvalidArgumentException(static::ARRAY_MSG);
  7799. }
  7800. throw new \TypeError(sprintf(static::INVALID_TYPE_MSG, gettype($subject)));
  7801. }
  7802. $result = preg_replace($pattern, $replacement, $subject, $limit, $count);
  7803. if ($result === null) {
  7804. throw PcreException::fromFunction('preg_replace', $pattern);
  7805. }
  7806. return $result;
  7807. }
  7808. /**
  7809. @param-out
  7810. */
  7811. public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string
  7812. {
  7813. if (!is_scalar($subject)) {
  7814. if (is_array($subject)) {
  7815. throw new \InvalidArgumentException(static::ARRAY_MSG);
  7816. }
  7817. throw new \TypeError(sprintf(static::INVALID_TYPE_MSG, gettype($subject)));
  7818. }
  7819. $result = preg_replace_callback($pattern, $replacement, $subject, $limit, $count, $flags | PREG_UNMATCHED_AS_NULL);
  7820. if ($result === null) {
  7821. throw PcreException::fromFunction('preg_replace_callback', $pattern);
  7822. }
  7823. return $result;
  7824. }
  7825. /**
  7826. @param-out
  7827. */
  7828. public static function replaceCallbackStrictGroups(string $pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string
  7829. {
  7830. return self::replaceCallback($pattern, function (array $matches) use ($pattern, $replacement) {
  7831. return $replacement(self::enforceNonNullMatches($pattern, $matches, 'replaceCallback'));
  7832. }, $subject, $limit, $count, $flags);
  7833. }
  7834. /**
  7835. @param-out
  7836. */
  7837. public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string
  7838. {
  7839. if (!is_scalar($subject)) {
  7840. if (is_array($subject)) {
  7841. throw new \InvalidArgumentException(static::ARRAY_MSG);
  7842. }
  7843. throw new \TypeError(sprintf(static::INVALID_TYPE_MSG, gettype($subject)));
  7844. }
  7845. $result = preg_replace_callback_array($pattern, $subject, $limit, $count, $flags | PREG_UNMATCHED_AS_NULL);
  7846. if ($result === null) {
  7847. $pattern = array_keys($pattern);
  7848. throw PcreException::fromFunction('preg_replace_callback_array', $pattern);
  7849. }
  7850. return $result;
  7851. }
  7852. public static function split(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
  7853. {
  7854. if (($flags & PREG_SPLIT_OFFSET_CAPTURE) !== 0) {
  7855. throw new \InvalidArgumentException('PREG_SPLIT_OFFSET_CAPTURE is not supported as it changes the type of $matches, use splitWithOffsets() instead');
  7856. }
  7857. $result = preg_split($pattern, $subject, $limit, $flags);
  7858. if ($result === false) {
  7859. throw PcreException::fromFunction('preg_split', $pattern);
  7860. }
  7861. return $result;
  7862. }
  7863. /**
  7864. @phpstan-return
  7865. */
  7866. public static function splitWithOffsets(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
  7867. {
  7868. $result = preg_split($pattern, $subject, $limit, $flags | PREG_SPLIT_OFFSET_CAPTURE);
  7869. if ($result === false) {
  7870. throw PcreException::fromFunction('preg_split', $pattern);
  7871. }
  7872. return $result;
  7873. }
  7874. /**
  7875. @template
  7876. */
  7877. public static function grep(string $pattern, array $array, int $flags = 0): array
  7878. {
  7879. $result = preg_grep($pattern, $array, $flags);
  7880. if ($result === false) {
  7881. throw PcreException::fromFunction('preg_grep', $pattern);
  7882. }
  7883. return $result;
  7884. }
  7885. /**
  7886. @param-out
  7887. */
  7888. public static function isMatch(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): bool
  7889. {
  7890. return (bool) static::match($pattern, $subject, $matches, $flags, $offset);
  7891. }
  7892. /**
  7893. @param-out
  7894. */
  7895. public static function isMatchStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): bool
  7896. {
  7897. return (bool) self::matchStrictGroups($pattern, $subject, $matches, $flags, $offset);
  7898. }
  7899. /**
  7900. @param-out
  7901. */
  7902. public static function isMatchAll(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): bool
  7903. {
  7904. return (bool) static::matchAll($pattern, $subject, $matches, $flags, $offset);
  7905. }
  7906. /**
  7907. @param-out
  7908. */
  7909. public static function isMatchAllStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): bool
  7910. {
  7911. return (bool) self::matchAllStrictGroups($pattern, $subject, $matches, $flags, $offset);
  7912. }
  7913. /**
  7914. @param-out
  7915. */
  7916. public static function isMatchWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0): bool
  7917. {
  7918. return (bool) static::matchWithOffsets($pattern, $subject, $matches, $flags, $offset);
  7919. }
  7920. /**
  7921. @param-out
  7922. */
  7923. public static function isMatchAllWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0): bool
  7924. {
  7925. return (bool) static::matchAllWithOffsets($pattern, $subject, $matches, $flags, $offset);
  7926. }
  7927. private static function checkOffsetCapture(int $flags, string $useFunctionName): void
  7928. {
  7929. if (($flags & PREG_OFFSET_CAPTURE) !== 0) {
  7930. throw new \InvalidArgumentException('PREG_OFFSET_CAPTURE is not supported as it changes the type of $matches, use ' . $useFunctionName . '() instead');
  7931. }
  7932. }
  7933. private static function checkSetOrder(int $flags): void
  7934. {
  7935. if (($flags & PREG_SET_ORDER) !== 0) {
  7936. throw new \InvalidArgumentException('PREG_SET_ORDER is not supported as it changes the type of $matches');
  7937. }
  7938. }
  7939. private static function enforceNonNullMatches(string $pattern, array $matches, string $variantMethod)
  7940. {
  7941. foreach ($matches as $group => $match) {
  7942. if (is_string($match) || (is_array($match) && is_string($match[0]))) {
  7943. continue;
  7944. }
  7945. throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.');
  7946. }
  7947. return $matches;
  7948. }
  7949. private static function enforceNonNullMatchAll(string $pattern, array $matches, string $variantMethod)
  7950. {
  7951. foreach ($matches as $group => $groupMatches) {
  7952. foreach ($groupMatches as $match) {
  7953. if (null === $match) {
  7954. throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.');
  7955. }
  7956. }
  7957. }
  7958. return $matches;
  7959. }
  7960. }
  7961. <?php
  7962. namespace Composer\Pcre;
  7963. class PcreException extends \RuntimeException
  7964. {
  7965. public static function fromFunction($function, $pattern)
  7966. {
  7967. $code = preg_last_error();
  7968. if (is_array($pattern)) {
  7969. $pattern = implode(', ', $pattern);
  7970. }
  7971. return new PcreException($function.'(): failed executing "'.$pattern.'": '.self::pcreLastErrorMessage($code), $code);
  7972. }
  7973. private static function pcreLastErrorMessage($code)
  7974. {
  7975. if (function_exists('preg_last_error_msg')) {
  7976. return preg_last_error_msg();
  7977. }
  7978. $constants = get_defined_constants(true);
  7979. if (!isset($constants['pcre']) || !is_array($constants['pcre'])) {
  7980. return 'UNDEFINED_ERROR';
  7981. }
  7982. foreach ($constants['pcre'] as $const => $val) {
  7983. if ($val === $code && substr($const, -6) === '_ERROR') {
  7984. return $const;
  7985. }
  7986. }
  7987. return 'UNDEFINED_ERROR';
  7988. }
  7989. }
  7990. <?php
  7991. declare(strict_types=1);
  7992. namespace Psr\EventDispatcher;
  7993. interface ListenerProviderInterface
  7994. {
  7995. public function getListenersForEvent(object $event) : iterable;
  7996. }
  7997. <?php
  7998. declare(strict_types=1);
  7999. namespace Psr\EventDispatcher;
  8000. interface EventDispatcherInterface
  8001. {
  8002. public function dispatch(object $event);
  8003. }
  8004. <?php
  8005. declare(strict_types=1);
  8006. namespace Psr\EventDispatcher;
  8007. interface StoppableEventInterface
  8008. {
  8009. public function isPropagationStopped() : bool;
  8010. }
  8011. <?php
  8012. namespace Psr\Container;
  8013. interface NotFoundExceptionInterface extends ContainerExceptionInterface
  8014. {
  8015. }
  8016. <?php
  8017. declare(strict_types=1);
  8018. namespace Psr\Container;
  8019. interface ContainerInterface
  8020. {
  8021. public function get(string $id);
  8022. public function has(string $id);
  8023. }
  8024. <?php
  8025. namespace Psr\Container;
  8026. use Throwable;
  8027. interface ContainerExceptionInterface extends Throwable
  8028. {
  8029. }
  8030. <?php
  8031. namespace Psr\Log;
  8032. interface LoggerAwareInterface
  8033. {
  8034. public function setLogger(LoggerInterface $logger);
  8035. }
  8036. <?php
  8037. namespace Psr\Log;
  8038. class LogLevel
  8039. {
  8040. const EMERGENCY = 'emergency';
  8041. const ALERT = 'alert';
  8042. const CRITICAL = 'critical';
  8043. const ERROR = 'error';
  8044. const WARNING = 'warning';
  8045. const NOTICE = 'notice';
  8046. const INFO = 'info';
  8047. const DEBUG = 'debug';
  8048. }
  8049. <?php
  8050. namespace Psr\Log;
  8051. trait LoggerAwareTrait
  8052. {
  8053. protected $logger;
  8054. public function setLogger(LoggerInterface $logger)
  8055. {
  8056. $this->logger = $logger;
  8057. }
  8058. }
  8059. <?php
  8060. namespace Psr\Log;
  8061. class InvalidArgumentException extends \InvalidArgumentException
  8062. {
  8063. }
  8064. <?php
  8065. namespace Psr\Log;
  8066. class NullLogger extends AbstractLogger
  8067. {
  8068. public function log($level, $message, array $context = array())
  8069. {
  8070. }
  8071. }
  8072. <?php
  8073. namespace Psr\Log;
  8074. interface LoggerInterface
  8075. {
  8076. public function emergency($message, array $context = array());
  8077. public function alert($message, array $context = array());
  8078. public function critical($message, array $context = array());
  8079. public function error($message, array $context = array());
  8080. public function warning($message, array $context = array());
  8081. public function notice($message, array $context = array());
  8082. public function info($message, array $context = array());
  8083. public function debug($message, array $context = array());
  8084. public function log($level, $message, array $context = array());
  8085. }
  8086. <?php
  8087. namespace Psr\Log;
  8088. trait LoggerTrait
  8089. {
  8090. public function emergency($message, array $context = array())
  8091. {
  8092. $this->log(LogLevel::EMERGENCY, $message, $context);
  8093. }
  8094. public function alert($message, array $context = array())
  8095. {
  8096. $this->log(LogLevel::ALERT, $message, $context);
  8097. }
  8098. public function critical($message, array $context = array())
  8099. {
  8100. $this->log(LogLevel::CRITICAL, $message, $context);
  8101. }
  8102. public function error($message, array $context = array())
  8103. {
  8104. $this->log(LogLevel::ERROR, $message, $context);
  8105. }
  8106. public function warning($message, array $context = array())
  8107. {
  8108. $this->log(LogLevel::WARNING, $message, $context);
  8109. }
  8110. public function notice($message, array $context = array())
  8111. {
  8112. $this->log(LogLevel::NOTICE, $message, $context);
  8113. }
  8114. public function info($message, array $context = array())
  8115. {
  8116. $this->log(LogLevel::INFO, $message, $context);
  8117. }
  8118. public function debug($message, array $context = array())
  8119. {
  8120. $this->log(LogLevel::DEBUG, $message, $context);
  8121. }
  8122. abstract public function log($level, $message, array $context = array());
  8123. }
  8124. <?php
  8125. namespace Psr\Log;
  8126. abstract class AbstractLogger implements LoggerInterface
  8127. {
  8128. public function emergency($message, array $context = array())
  8129. {
  8130. $this->log(LogLevel::EMERGENCY, $message, $context);
  8131. }
  8132. public function alert($message, array $context = array())
  8133. {
  8134. $this->log(LogLevel::ALERT, $message, $context);
  8135. }
  8136. public function critical($message, array $context = array())
  8137. {
  8138. $this->log(LogLevel::CRITICAL, $message, $context);
  8139. }
  8140. public function error($message, array $context = array())
  8141. {
  8142. $this->log(LogLevel::ERROR, $message, $context);
  8143. }
  8144. public function warning($message, array $context = array())
  8145. {
  8146. $this->log(LogLevel::WARNING, $message, $context);
  8147. }
  8148. public function notice($message, array $context = array())
  8149. {
  8150. $this->log(LogLevel::NOTICE, $message, $context);
  8151. }
  8152. public function info($message, array $context = array())
  8153. {
  8154. $this->log(LogLevel::INFO, $message, $context);
  8155. }
  8156. public function debug($message, array $context = array())
  8157. {
  8158. $this->log(LogLevel::DEBUG, $message, $context);
  8159. }
  8160. }
  8161. <?php
  8162. namespace Symfony\Polyfill\Php73;
  8163. final class Php73
  8164. {
  8165. public static $startAt = 1533462603;
  8166. public static function hrtime($asNum = false)
  8167. {
  8168. $ns = microtime(false);
  8169. $s = substr($ns, 11) - self::$startAt;
  8170. $ns = 1E9 * (float) $ns;
  8171. if ($asNum) {
  8172. $ns += $s * 1E9;
  8173. return \PHP_INT_SIZE === 4 ? $ns : (int) $ns;
  8174. }
  8175. return [$s, (int) $ns];
  8176. }
  8177. }
  8178. <?php
  8179. if (\PHP_VERSION_ID < 70300) {
  8180. class JsonException extends Exception
  8181. {
  8182. }
  8183. }
  8184. <?php
  8185. use Symfony\Polyfill\Php73 as p;
  8186. if (\PHP_VERSION_ID >= 70300) {
  8187. return;
  8188. }
  8189. if (!function_exists('is_countable')) {
  8190. function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
  8191. }
  8192. if (!function_exists('hrtime')) {
  8193. require_once __DIR__.'/Php73.php';
  8194. p\Php73::$startAt = (int) microtime(true);
  8195. function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
  8196. }
  8197. if (!function_exists('array_key_first')) {
  8198. function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
  8199. }
  8200. if (!function_exists('array_key_last')) {
  8201. function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
  8202. }
  8203. <?php
  8204. namespace Symfony\Polyfill\Php80;
  8205. class PhpToken implements \Stringable
  8206. {
  8207. public $id;
  8208. public $text;
  8209. public $line;
  8210. public $pos;
  8211. public function __construct(int $id, string $text, int $line = -1, int $position = -1)
  8212. {
  8213. $this->id = $id;
  8214. $this->text = $text;
  8215. $this->line = $line;
  8216. $this->pos = $position;
  8217. }
  8218. public function getTokenName(): ?string
  8219. {
  8220. if ('UNKNOWN' === $name = token_name($this->id)) {
  8221. $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
  8222. }
  8223. return $name;
  8224. }
  8225. public function is($kind): bool
  8226. {
  8227. foreach ((array) $kind as $value) {
  8228. if (\in_array($value, [$this->id, $this->text], true)) {
  8229. return true;
  8230. }
  8231. }
  8232. return false;
  8233. }
  8234. public function isIgnorable(): bool
  8235. {
  8236. return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
  8237. }
  8238. public function __toString(): string
  8239. {
  8240. return (string) $this->text;
  8241. }
  8242. public static function tokenize(string $code, int $flags = 0): array
  8243. {
  8244. $line = 1;
  8245. $position = 0;
  8246. $tokens = token_get_all($code, $flags);
  8247. foreach ($tokens as $index => $token) {
  8248. if (\is_string($token)) {
  8249. $id = \ord($token);
  8250. $text = $token;
  8251. } else {
  8252. [$id, $text, $line] = $token;
  8253. }
  8254. $tokens[$index] = new static($id, $text, $line, $position);
  8255. $position += \strlen($text);
  8256. }
  8257. return $tokens;
  8258. }
  8259. }
  8260. <?php
  8261. if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
  8262. class PhpToken extends Symfony\Polyfill\Php80\PhpToken
  8263. {
  8264. }
  8265. }
  8266. <?php
  8267. if (\PHP_VERSION_ID < 80000) {
  8268. class ValueError extends Error
  8269. {
  8270. }
  8271. }
  8272. <?php
  8273. #[Attribute(Attribute::TARGET_CLASS)]
  8274. final class Attribute
  8275. {
  8276. public const TARGET_CLASS = 1;
  8277. public const TARGET_FUNCTION = 2;
  8278. public const TARGET_METHOD = 4;
  8279. public const TARGET_PROPERTY = 8;
  8280. public const TARGET_CLASS_CONSTANT = 16;
  8281. public const TARGET_PARAMETER = 32;
  8282. public const TARGET_ALL = 63;
  8283. public const IS_REPEATABLE = 64;
  8284. public $flags;
  8285. public function __construct(int $flags = self::TARGET_ALL)
  8286. {
  8287. $this->flags = $flags;
  8288. }
  8289. }
  8290. <?php
  8291. if (\PHP_VERSION_ID < 80000) {
  8292. class UnhandledMatchError extends Error
  8293. {
  8294. }
  8295. }
  8296. <?php
  8297. if (\PHP_VERSION_ID < 80000) {
  8298. interface Stringable
  8299. {
  8300. public function __toString();
  8301. }
  8302. }
  8303. <?php
  8304. use Symfony\Polyfill\Php80 as p;
  8305. if (\PHP_VERSION_ID >= 80000) {
  8306. return;
  8307. }
  8308. if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
  8309. define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
  8310. }
  8311. if (!function_exists('fdiv')) {
  8312. function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
  8313. }
  8314. if (!function_exists('preg_last_error_msg')) {
  8315. function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
  8316. }
  8317. if (!function_exists('str_contains')) {
  8318. function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
  8319. }
  8320. if (!function_exists('str_starts_with')) {
  8321. function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
  8322. }
  8323. if (!function_exists('str_ends_with')) {
  8324. function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
  8325. }
  8326. if (!function_exists('get_debug_type')) {
  8327. function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
  8328. }
  8329. if (!function_exists('get_resource_id')) {
  8330. function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
  8331. }
  8332. <?php
  8333. namespace Symfony\Polyfill\Php80;
  8334. final class Php80
  8335. {
  8336. public static function fdiv(float $dividend, float $divisor): float
  8337. {
  8338. return @($dividend / $divisor);
  8339. }
  8340. public static function get_debug_type($value): string
  8341. {
  8342. switch (true) {
  8343. case null === $value: return 'null';
  8344. case \is_bool($value): return 'bool';
  8345. case \is_string($value): return 'string';
  8346. case \is_array($value): return 'array';
  8347. case \is_int($value): return 'int';
  8348. case \is_float($value): return 'float';
  8349. case \is_object($value): break;
  8350. case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
  8351. default:
  8352. if (null === $type = @get_resource_type($value)) {
  8353. return 'unknown';
  8354. }
  8355. if ('Unknown' === $type) {
  8356. $type = 'closed';
  8357. }
  8358. return "resource ($type)";
  8359. }
  8360. $class = \get_class($value);
  8361. if (false === strpos($class, '@')) {
  8362. return $class;
  8363. }
  8364. return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
  8365. }
  8366. public static function get_resource_id($res): int
  8367. {
  8368. if (!\is_resource($res) && null === @get_resource_type($res)) {
  8369. throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
  8370. }
  8371. return (int) $res;
  8372. }
  8373. public static function preg_last_error_msg(): string
  8374. {
  8375. switch (preg_last_error()) {
  8376. case \PREG_INTERNAL_ERROR:
  8377. return 'Internal error';
  8378. case \PREG_BAD_UTF8_ERROR:
  8379. return 'Malformed UTF-8 characters, possibly incorrectly encoded';
  8380. case \PREG_BAD_UTF8_OFFSET_ERROR:
  8381. return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
  8382. case \PREG_BACKTRACK_LIMIT_ERROR:
  8383. return 'Backtrack limit exhausted';
  8384. case \PREG_RECURSION_LIMIT_ERROR:
  8385. return 'Recursion limit exhausted';
  8386. case \PREG_JIT_STACKLIMIT_ERROR:
  8387. return 'JIT stack limit exhausted';
  8388. case \PREG_NO_ERROR:
  8389. return 'No error';
  8390. default:
  8391. return 'Unknown error';
  8392. }
  8393. }
  8394. public static function str_contains(string $haystack, string $needle): bool
  8395. {
  8396. return '' === $needle || false !== strpos($haystack, $needle);
  8397. }
  8398. public static function str_starts_with(string $haystack, string $needle): bool
  8399. {
  8400. return 0 === strncmp($haystack, $needle, \strlen($needle));
  8401. }
  8402. public static function str_ends_with(string $haystack, string $needle): bool
  8403. {
  8404. if ('' === $needle || $needle === $haystack) {
  8405. return true;
  8406. }
  8407. if ('' === $haystack) {
  8408. return false;
  8409. }
  8410. $needleLength = \strlen($needle);
  8411. return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
  8412. }
  8413. }
  8414. <?php
  8415. use Symfony\Polyfill\Ctype as p;
  8416. if (!function_exists('ctype_alnum')) {
  8417. function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
  8418. }
  8419. if (!function_exists('ctype_alpha')) {
  8420. function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
  8421. }
  8422. if (!function_exists('ctype_cntrl')) {
  8423. function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
  8424. }
  8425. if (!function_exists('ctype_digit')) {
  8426. function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
  8427. }
  8428. if (!function_exists('ctype_graph')) {
  8429. function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
  8430. }
  8431. if (!function_exists('ctype_lower')) {
  8432. function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
  8433. }
  8434. if (!function_exists('ctype_print')) {
  8435. function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
  8436. }
  8437. if (!function_exists('ctype_punct')) {
  8438. function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
  8439. }
  8440. if (!function_exists('ctype_space')) {
  8441. function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
  8442. }
  8443. if (!function_exists('ctype_upper')) {
  8444. function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
  8445. }
  8446. if (!function_exists('ctype_xdigit')) {
  8447. function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
  8448. }
  8449. <?php
  8450. use Symfony\Polyfill\Ctype as p;
  8451. if (\PHP_VERSION_ID >= 80000) {
  8452. return require __DIR__.'/bootstrap80.php';
  8453. }
  8454. if (!function_exists('ctype_alnum')) {
  8455. function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
  8456. }
  8457. if (!function_exists('ctype_alpha')) {
  8458. function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
  8459. }
  8460. if (!function_exists('ctype_cntrl')) {
  8461. function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
  8462. }
  8463. if (!function_exists('ctype_digit')) {
  8464. function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
  8465. }
  8466. if (!function_exists('ctype_graph')) {
  8467. function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
  8468. }
  8469. if (!function_exists('ctype_lower')) {
  8470. function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
  8471. }
  8472. if (!function_exists('ctype_print')) {
  8473. function ctype_print($text) { return p\Ctype::ctype_print($text); }
  8474. }
  8475. if (!function_exists('ctype_punct')) {
  8476. function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
  8477. }
  8478. if (!function_exists('ctype_space')) {
  8479. function ctype_space($text) { return p\Ctype::ctype_space($text); }
  8480. }
  8481. if (!function_exists('ctype_upper')) {
  8482. function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
  8483. }
  8484. if (!function_exists('ctype_xdigit')) {
  8485. function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
  8486. }
  8487. <?php
  8488. namespace Symfony\Polyfill\Ctype;
  8489. final class Ctype
  8490. {
  8491. public static function ctype_alnum($text)
  8492. {
  8493. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8494. return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
  8495. }
  8496. public static function ctype_alpha($text)
  8497. {
  8498. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8499. return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
  8500. }
  8501. public static function ctype_cntrl($text)
  8502. {
  8503. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8504. return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
  8505. }
  8506. public static function ctype_digit($text)
  8507. {
  8508. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8509. return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
  8510. }
  8511. public static function ctype_graph($text)
  8512. {
  8513. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8514. return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
  8515. }
  8516. public static function ctype_lower($text)
  8517. {
  8518. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8519. return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
  8520. }
  8521. public static function ctype_print($text)
  8522. {
  8523. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8524. return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
  8525. }
  8526. public static function ctype_punct($text)
  8527. {
  8528. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8529. return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
  8530. }
  8531. public static function ctype_space($text)
  8532. {
  8533. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8534. return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
  8535. }
  8536. public static function ctype_upper($text)
  8537. {
  8538. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8539. return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
  8540. }
  8541. public static function ctype_xdigit($text)
  8542. {
  8543. $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
  8544. return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
  8545. }
  8546. private static function convert_int_to_char_for_ctype($int, $function)
  8547. {
  8548. if (!\is_int($int)) {
  8549. return $int;
  8550. }
  8551. if ($int < -128 || $int > 255) {
  8552. return (string) $int;
  8553. }
  8554. if (\PHP_VERSION_ID >= 80100) {
  8555. @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
  8556. }
  8557. if ($int < 0) {
  8558. $int += 256;
  8559. }
  8560. return \chr($int);
  8561. }
  8562. }
  8563. <?php
  8564. if (\PHP_VERSION_ID < 80100) {
  8565. #[Attribute(Attribute::TARGET_METHOD)]
  8566. final class ReturnTypeWillChange
  8567. {
  8568. public function __construct()
  8569. {
  8570. }
  8571. }
  8572. }
  8573. <?php
  8574. if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) {
  8575. class CURLStringFile extends CURLFile
  8576. {
  8577. private $data;
  8578. public function __construct(string $data, string $postname, string $mime = 'application/octet-stream')
  8579. {
  8580. $this->data = $data;
  8581. parent::__construct('data://application/octet-stream;base64,'.base64_encode($data), $mime, $postname);
  8582. }
  8583. public function __set(string $name, $value): void
  8584. {
  8585. if ('data' !== $name) {
  8586. $this->$name = $value;
  8587. return;
  8588. }
  8589. if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) {
  8590. throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string');
  8591. }
  8592. $this->name = 'data://application/octet-stream;base64,'.base64_encode($value);
  8593. }
  8594. public function __isset(string $name): bool
  8595. {
  8596. return isset($this->$name);
  8597. }
  8598. public function &__get(string $name)
  8599. {
  8600. return $this->$name;
  8601. }
  8602. }
  8603. }
  8604. <?php
  8605. use Symfony\Polyfill\Php81 as p;
  8606. if (\PHP_VERSION_ID >= 80100) {
  8607. return;
  8608. }
  8609. if (defined('MYSQLI_REFRESH_SLAVE') && !defined('MYSQLI_REFRESH_REPLICA')) {
  8610. define('MYSQLI_REFRESH_REPLICA', 64);
  8611. }
  8612. if (!function_exists('array_is_list')) {
  8613. function array_is_list(array $array): bool { return p\Php81::array_is_list($array); }
  8614. }
  8615. if (!function_exists('enum_exists')) {
  8616. function enum_exists(string $enum, bool $autoload = true): bool { return $autoload && class_exists($enum) && false; }
  8617. }
  8618. <?php
  8619. namespace Symfony\Polyfill\Php81;
  8620. final class Php81
  8621. {
  8622. public static function array_is_list(array $array): bool
  8623. {
  8624. if ([] === $array || $array === array_values($array)) {
  8625. return true;
  8626. }
  8627. $nextKey = -1;
  8628. foreach ($array as $k => $v) {
  8629. if ($k !== ++$nextKey) {
  8630. return false;
  8631. }
  8632. }
  8633. return true;
  8634. }
  8635. }
  8636. <?php
  8637. namespace Symfony\Component\EventDispatcher;
  8638. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
  8639. interface EventDispatcherInterface extends ContractsEventDispatcherInterface
  8640. {
  8641. public function addListener(string $eventName, callable $listener, int $priority = 0);
  8642. public function addSubscriber(EventSubscriberInterface $subscriber);
  8643. public function removeListener(string $eventName, callable $listener);
  8644. public function removeSubscriber(EventSubscriberInterface $subscriber);
  8645. public function getListeners(?string $eventName = null);
  8646. public function getListenerPriority(string $eventName, callable $listener);
  8647. public function hasListeners(?string $eventName = null);
  8648. }
  8649. <?php
  8650. namespace Symfony\Component\EventDispatcher\Attribute;
  8651. #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
  8652. class AsEventListener
  8653. {
  8654. public function __construct(
  8655. public ?string $event = null,
  8656. public ?string $method = null,
  8657. public int $priority = 0,
  8658. public ?string $dispatcher = null,
  8659. ) {
  8660. }
  8661. }
  8662. <?php
  8663. namespace Symfony\Component\EventDispatcher;
  8664. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  8665. trigger_deprecation('symfony/event-dispatcher', '5.1', '%s is deprecated, use the event dispatcher without the proxy.', LegacyEventDispatcherProxy::class);
  8666. final class LegacyEventDispatcherProxy
  8667. {
  8668. public static function decorate(?EventDispatcherInterface $dispatcher): ?EventDispatcherInterface
  8669. {
  8670. return $dispatcher;
  8671. }
  8672. }
  8673. <?php
  8674. namespace Symfony\Component\EventDispatcher;
  8675. use Psr\EventDispatcher\StoppableEventInterface;
  8676. use Symfony\Component\EventDispatcher\Debug\WrappedListener;
  8677. class EventDispatcher implements EventDispatcherInterface
  8678. {
  8679. private $listeners = [];
  8680. private $sorted = [];
  8681. private $optimized;
  8682. public function __construct()
  8683. {
  8684. if (__CLASS__ === static::class) {
  8685. $this->optimized = [];
  8686. }
  8687. }
  8688. public function dispatch(object $event, ?string $eventName = null): object
  8689. {
  8690. $eventName = $eventName ?? \get_class($event);
  8691. if (null !== $this->optimized) {
  8692. $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
  8693. } else {
  8694. $listeners = $this->getListeners($eventName);
  8695. }
  8696. if ($listeners) {
  8697. $this->callListeners($listeners, $eventName, $event);
  8698. }
  8699. return $event;
  8700. }
  8701. public function getListeners(?string $eventName = null)
  8702. {
  8703. if (null !== $eventName) {
  8704. if (empty($this->listeners[$eventName])) {
  8705. return [];
  8706. }
  8707. if (!isset($this->sorted[$eventName])) {
  8708. $this->sortListeners($eventName);
  8709. }
  8710. return $this->sorted[$eventName];
  8711. }
  8712. foreach ($this->listeners as $eventName => $eventListeners) {
  8713. if (!isset($this->sorted[$eventName])) {
  8714. $this->sortListeners($eventName);
  8715. }
  8716. }
  8717. return array_filter($this->sorted);
  8718. }
  8719. public function getListenerPriority(string $eventName, $listener)
  8720. {
  8721. if (empty($this->listeners[$eventName])) {
  8722. return null;
  8723. }
  8724. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
  8725. $listener[0] = $listener[0]();
  8726. $listener[1] = $listener[1] ?? '__invoke';
  8727. }
  8728. foreach ($this->listeners[$eventName] as $priority => &$listeners) {
  8729. foreach ($listeners as &$v) {
  8730. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
  8731. $v[0] = $v[0]();
  8732. $v[1] = $v[1] ?? '__invoke';
  8733. }
  8734. if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
  8735. return $priority;
  8736. }
  8737. }
  8738. }
  8739. return null;
  8740. }
  8741. public function hasListeners(?string $eventName = null)
  8742. {
  8743. if (null !== $eventName) {
  8744. return !empty($this->listeners[$eventName]);
  8745. }
  8746. foreach ($this->listeners as $eventListeners) {
  8747. if ($eventListeners) {
  8748. return true;
  8749. }
  8750. }
  8751. return false;
  8752. }
  8753. public function addListener(string $eventName, $listener, int $priority = 0)
  8754. {
  8755. $this->listeners[$eventName][$priority][] = $listener;
  8756. unset($this->sorted[$eventName], $this->optimized[$eventName]);
  8757. }
  8758. public function removeListener(string $eventName, $listener)
  8759. {
  8760. if (empty($this->listeners[$eventName])) {
  8761. return;
  8762. }
  8763. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
  8764. $listener[0] = $listener[0]();
  8765. $listener[1] = $listener[1] ?? '__invoke';
  8766. }
  8767. foreach ($this->listeners[$eventName] as $priority => &$listeners) {
  8768. foreach ($listeners as $k => &$v) {
  8769. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
  8770. $v[0] = $v[0]();
  8771. $v[1] = $v[1] ?? '__invoke';
  8772. }
  8773. if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
  8774. unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
  8775. }
  8776. }
  8777. if (!$listeners) {
  8778. unset($this->listeners[$eventName][$priority]);
  8779. }
  8780. }
  8781. }
  8782. public function addSubscriber(EventSubscriberInterface $subscriber)
  8783. {
  8784. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  8785. if (\is_string($params)) {
  8786. $this->addListener($eventName, [$subscriber, $params]);
  8787. } elseif (\is_string($params[0])) {
  8788. $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0);
  8789. } else {
  8790. foreach ($params as $listener) {
  8791. $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0);
  8792. }
  8793. }
  8794. }
  8795. }
  8796. public function removeSubscriber(EventSubscriberInterface $subscriber)
  8797. {
  8798. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  8799. if (\is_array($params) && \is_array($params[0])) {
  8800. foreach ($params as $listener) {
  8801. $this->removeListener($eventName, [$subscriber, $listener[0]]);
  8802. }
  8803. } else {
  8804. $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
  8805. }
  8806. }
  8807. }
  8808. protected function callListeners(iterable $listeners, string $eventName, object $event)
  8809. {
  8810. $stoppable = $event instanceof StoppableEventInterface;
  8811. foreach ($listeners as $listener) {
  8812. if ($stoppable && $event->isPropagationStopped()) {
  8813. break;
  8814. }
  8815. $listener($event, $eventName, $this);
  8816. }
  8817. }
  8818. private function sortListeners(string $eventName)
  8819. {
  8820. krsort($this->listeners[$eventName]);
  8821. $this->sorted[$eventName] = [];
  8822. foreach ($this->listeners[$eventName] as &$listeners) {
  8823. foreach ($listeners as $k => &$listener) {
  8824. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
  8825. $listener[0] = $listener[0]();
  8826. $listener[1] = $listener[1] ?? '__invoke';
  8827. }
  8828. $this->sorted[$eventName][] = $listener;
  8829. }
  8830. }
  8831. }
  8832. private function optimizeListeners(string $eventName): array
  8833. {
  8834. krsort($this->listeners[$eventName]);
  8835. $this->optimized[$eventName] = [];
  8836. foreach ($this->listeners[$eventName] as &$listeners) {
  8837. foreach ($listeners as &$listener) {
  8838. $closure = &$this->optimized[$eventName][];
  8839. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
  8840. $closure = static function (...$args) use (&$listener, &$closure) {
  8841. if ($listener[0] instanceof \Closure) {
  8842. $listener[0] = $listener[0]();
  8843. $listener[1] = $listener[1] ?? '__invoke';
  8844. }
  8845. ($closure = \Closure::fromCallable($listener))(...$args);
  8846. };
  8847. } else {
  8848. $closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure::fromCallable($listener);
  8849. }
  8850. }
  8851. }
  8852. return $this->optimized[$eventName];
  8853. }
  8854. }
  8855. <?php
  8856. namespace Symfony\Component\EventDispatcher;
  8857. interface EventSubscriberInterface
  8858. {
  8859. public static function getSubscribedEvents();
  8860. }
  8861. <?php
  8862. namespace Symfony\Component\EventDispatcher;
  8863. class ImmutableEventDispatcher implements EventDispatcherInterface
  8864. {
  8865. private $dispatcher;
  8866. public function __construct(EventDispatcherInterface $dispatcher)
  8867. {
  8868. $this->dispatcher = $dispatcher;
  8869. }
  8870. public function dispatch(object $event, ?string $eventName = null): object
  8871. {
  8872. return $this->dispatcher->dispatch($event, $eventName);
  8873. }
  8874. public function addListener(string $eventName, $listener, int $priority = 0)
  8875. {
  8876. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  8877. }
  8878. public function addSubscriber(EventSubscriberInterface $subscriber)
  8879. {
  8880. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  8881. }
  8882. public function removeListener(string $eventName, $listener)
  8883. {
  8884. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  8885. }
  8886. public function removeSubscriber(EventSubscriberInterface $subscriber)
  8887. {
  8888. throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
  8889. }
  8890. public function getListeners(?string $eventName = null)
  8891. {
  8892. return $this->dispatcher->getListeners($eventName);
  8893. }
  8894. public function getListenerPriority(string $eventName, $listener)
  8895. {
  8896. return $this->dispatcher->getListenerPriority($eventName, $listener);
  8897. }
  8898. public function hasListeners(?string $eventName = null)
  8899. {
  8900. return $this->dispatcher->hasListeners($eventName);
  8901. }
  8902. }
  8903. <?php
  8904. namespace Symfony\Component\EventDispatcher;
  8905. use Symfony\Contracts\EventDispatcher\Event;
  8906. /**
  8907. @implements
  8908. @implements
  8909. */
  8910. class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
  8911. {
  8912. protected $subject;
  8913. protected $arguments;
  8914. public function __construct($subject = null, array $arguments = [])
  8915. {
  8916. $this->subject = $subject;
  8917. $this->arguments = $arguments;
  8918. }
  8919. public function getSubject()
  8920. {
  8921. return $this->subject;
  8922. }
  8923. public function getArgument(string $key)
  8924. {
  8925. if ($this->hasArgument($key)) {
  8926. return $this->arguments[$key];
  8927. }
  8928. throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key));
  8929. }
  8930. public function setArgument(string $key, $value)
  8931. {
  8932. $this->arguments[$key] = $value;
  8933. return $this;
  8934. }
  8935. public function getArguments()
  8936. {
  8937. return $this->arguments;
  8938. }
  8939. public function setArguments(array $args = [])
  8940. {
  8941. $this->arguments = $args;
  8942. return $this;
  8943. }
  8944. public function hasArgument(string $key)
  8945. {
  8946. return \array_key_exists($key, $this->arguments);
  8947. }
  8948. #[\ReturnTypeWillChange]
  8949. public function offsetGet($key)
  8950. {
  8951. return $this->getArgument($key);
  8952. }
  8953. #[\ReturnTypeWillChange]
  8954. public function offsetSet($key, $value)
  8955. {
  8956. $this->setArgument($key, $value);
  8957. }
  8958. #[\ReturnTypeWillChange]
  8959. public function offsetUnset($key)
  8960. {
  8961. if ($this->hasArgument($key)) {
  8962. unset($this->arguments[$key]);
  8963. }
  8964. }
  8965. #[\ReturnTypeWillChange]
  8966. public function offsetExists($key)
  8967. {
  8968. return $this->hasArgument($key);
  8969. }
  8970. #[\ReturnTypeWillChange]
  8971. public function getIterator()
  8972. {
  8973. return new \ArrayIterator($this->arguments);
  8974. }
  8975. }
  8976. <?php
  8977. namespace Symfony\Component\EventDispatcher\DependencyInjection;
  8978. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  8979. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  8980. use Symfony\Component\DependencyInjection\ContainerBuilder;
  8981. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  8982. use Symfony\Component\DependencyInjection\Reference;
  8983. use Symfony\Component\EventDispatcher\EventDispatcher;
  8984. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8985. use Symfony\Contracts\EventDispatcher\Event;
  8986. class RegisterListenersPass implements CompilerPassInterface
  8987. {
  8988. protected $dispatcherService;
  8989. protected $listenerTag;
  8990. protected $subscriberTag;
  8991. protected $eventAliasesParameter;
  8992. private $hotPathEvents = [];
  8993. private $hotPathTagName = 'container.hot_path';
  8994. private $noPreloadEvents = [];
  8995. private $noPreloadTagName = 'container.no_preload';
  8996. public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases')
  8997. {
  8998. if (0 < \func_num_args()) {
  8999. trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
  9000. }
  9001. $this->dispatcherService = $dispatcherService;
  9002. $this->listenerTag = $listenerTag;
  9003. $this->subscriberTag = $subscriberTag;
  9004. $this->eventAliasesParameter = $eventAliasesParameter;
  9005. }
  9006. public function setHotPathEvents(array $hotPathEvents)
  9007. {
  9008. $this->hotPathEvents = array_flip($hotPathEvents);
  9009. if (1 < \func_num_args()) {
  9010. trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
  9011. $this->hotPathTagName = func_get_arg(1);
  9012. }
  9013. return $this;
  9014. }
  9015. public function setNoPreloadEvents(array $noPreloadEvents): self
  9016. {
  9017. $this->noPreloadEvents = array_flip($noPreloadEvents);
  9018. if (1 < \func_num_args()) {
  9019. trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
  9020. $this->noPreloadTagName = func_get_arg(1);
  9021. }
  9022. return $this;
  9023. }
  9024. public function process(ContainerBuilder $container)
  9025. {
  9026. if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
  9027. return;
  9028. }
  9029. $aliases = [];
  9030. if ($container->hasParameter($this->eventAliasesParameter)) {
  9031. $aliases = $container->getParameter($this->eventAliasesParameter);
  9032. }
  9033. $globalDispatcherDefinition = $container->findDefinition($this->dispatcherService);
  9034. foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) {
  9035. $noPreload = 0;
  9036. foreach ($events as $event) {
  9037. $priority = $event['priority'] ?? 0;
  9038. if (!isset($event['event'])) {
  9039. if ($container->getDefinition($id)->hasTag($this->subscriberTag)) {
  9040. continue;
  9041. }
  9042. $event['method'] = $event['method'] ?? '__invoke';
  9043. $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']);
  9044. }
  9045. $event['event'] = $aliases[$event['event']] ?? $event['event'];
  9046. if (!isset($event['method'])) {
  9047. $event['method'] = 'on'.preg_replace_callback([
  9048. '/(?<=\b|_)[a-z]/i',
  9049. '/[^a-z0-9]/i',
  9050. ], function ($matches) { return strtoupper($matches[0]); }, $event['event']);
  9051. $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
  9052. if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) {
  9053. if (!$r->hasMethod('__invoke')) {
  9054. throw new InvalidArgumentException(sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "%s" tags.', $event['method'], $id, $this->listenerTag));
  9055. }
  9056. $event['method'] = '__invoke';
  9057. }
  9058. }
  9059. $dispatcherDefinition = $globalDispatcherDefinition;
  9060. if (isset($event['dispatcher'])) {
  9061. $dispatcherDefinition = $container->findDefinition($event['dispatcher']);
  9062. }
  9063. $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
  9064. if (isset($this->hotPathEvents[$event['event']])) {
  9065. $container->getDefinition($id)->addTag($this->hotPathTagName);
  9066. } elseif (isset($this->noPreloadEvents[$event['event']])) {
  9067. ++$noPreload;
  9068. }
  9069. }
  9070. if ($noPreload && \count($events) === $noPreload) {
  9071. $container->getDefinition($id)->addTag($this->noPreloadTagName);
  9072. }
  9073. }
  9074. $extractingDispatcher = new ExtractingEventDispatcher();
  9075. foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $tags) {
  9076. $def = $container->getDefinition($id);
  9077. $class = $def->getClass();
  9078. if (!$r = $container->getReflectionClass($class)) {
  9079. throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  9080. }
  9081. if (!$r->isSubclassOf(EventSubscriberInterface::class)) {
  9082. throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class));
  9083. }
  9084. $class = $r->name;
  9085. $dispatcherDefinitions = [];
  9086. foreach ($tags as $attributes) {
  9087. if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) {
  9088. continue;
  9089. }
  9090. $dispatcherDefinitions[$attributes['dispatcher']] = $container->findDefinition($attributes['dispatcher']);
  9091. }
  9092. if (!$dispatcherDefinitions) {
  9093. $dispatcherDefinitions = [$globalDispatcherDefinition];
  9094. }
  9095. $noPreload = 0;
  9096. ExtractingEventDispatcher::$aliases = $aliases;
  9097. ExtractingEventDispatcher::$subscriber = $class;
  9098. $extractingDispatcher->addSubscriber($extractingDispatcher);
  9099. foreach ($extractingDispatcher->listeners as $args) {
  9100. $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
  9101. foreach ($dispatcherDefinitions as $dispatcherDefinition) {
  9102. $dispatcherDefinition->addMethodCall('addListener', $args);
  9103. }
  9104. if (isset($this->hotPathEvents[$args[0]])) {
  9105. $container->getDefinition($id)->addTag($this->hotPathTagName);
  9106. } elseif (isset($this->noPreloadEvents[$args[0]])) {
  9107. ++$noPreload;
  9108. }
  9109. }
  9110. if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) {
  9111. $container->getDefinition($id)->addTag($this->noPreloadTagName);
  9112. }
  9113. $extractingDispatcher->listeners = [];
  9114. ExtractingEventDispatcher::$aliases = [];
  9115. }
  9116. }
  9117. private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string
  9118. {
  9119. if (
  9120. null === ($class = $container->getDefinition($id)->getClass())
  9121. || !($r = $container->getReflectionClass($class, false))
  9122. || !$r->hasMethod($method)
  9123. || 1 > ($m = $r->getMethod($method))->getNumberOfParameters()
  9124. || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
  9125. || $type->isBuiltin()
  9126. || Event::class === ($name = $type->getName())
  9127. ) {
  9128. throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
  9129. }
  9130. return $name;
  9131. }
  9132. }
  9133. class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface
  9134. {
  9135. public $listeners = [];
  9136. public static $aliases = [];
  9137. public static $subscriber;
  9138. public function addListener(string $eventName, $listener, int $priority = 0)
  9139. {
  9140. $this->listeners[] = [$eventName, $listener[1], $priority];
  9141. }
  9142. public static function getSubscribedEvents(): array
  9143. {
  9144. $events = [];
  9145. foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) {
  9146. $events[self::$aliases[$eventName] ?? $eventName] = $params;
  9147. }
  9148. return $events;
  9149. }
  9150. }
  9151. <?php
  9152. namespace Symfony\Component\EventDispatcher\DependencyInjection;
  9153. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  9154. use Symfony\Component\DependencyInjection\ContainerBuilder;
  9155. class AddEventAliasesPass implements CompilerPassInterface
  9156. {
  9157. private $eventAliases;
  9158. private $eventAliasesParameter;
  9159. public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases')
  9160. {
  9161. if (1 < \func_num_args()) {
  9162. trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
  9163. }
  9164. $this->eventAliases = $eventAliases;
  9165. $this->eventAliasesParameter = $eventAliasesParameter;
  9166. }
  9167. public function process(ContainerBuilder $container): void
  9168. {
  9169. $eventAliases = $container->hasParameter($this->eventAliasesParameter) ? $container->getParameter($this->eventAliasesParameter) : [];
  9170. $container->setParameter(
  9171. $this->eventAliasesParameter,
  9172. array_merge($eventAliases, $this->eventAliases)
  9173. );
  9174. }
  9175. }
  9176. <?php
  9177. namespace Symfony\Component\EventDispatcher\Debug;
  9178. use Psr\EventDispatcher\StoppableEventInterface;
  9179. use Psr\Log\LoggerInterface;
  9180. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  9181. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9182. use Symfony\Component\HttpFoundation\Request;
  9183. use Symfony\Component\HttpFoundation\RequestStack;
  9184. use Symfony\Component\Stopwatch\Stopwatch;
  9185. use Symfony\Contracts\Service\ResetInterface;
  9186. class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface
  9187. {
  9188. protected $logger;
  9189. protected $stopwatch;
  9190. private $callStack;
  9191. private $dispatcher;
  9192. private $wrappedListeners;
  9193. private $orphanedEvents;
  9194. private $requestStack;
  9195. private $currentRequestHash = '';
  9196. public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, ?LoggerInterface $logger = null, ?RequestStack $requestStack = null)
  9197. {
  9198. $this->dispatcher = $dispatcher;
  9199. $this->stopwatch = $stopwatch;
  9200. $this->logger = $logger;
  9201. $this->wrappedListeners = [];
  9202. $this->orphanedEvents = [];
  9203. $this->requestStack = $requestStack;
  9204. }
  9205. public function addListener(string $eventName, $listener, int $priority = 0)
  9206. {
  9207. $this->dispatcher->addListener($eventName, $listener, $priority);
  9208. }
  9209. public function addSubscriber(EventSubscriberInterface $subscriber)
  9210. {
  9211. $this->dispatcher->addSubscriber($subscriber);
  9212. }
  9213. public function removeListener(string $eventName, $listener)
  9214. {
  9215. if (isset($this->wrappedListeners[$eventName])) {
  9216. foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
  9217. if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
  9218. $listener = $wrappedListener;
  9219. unset($this->wrappedListeners[$eventName][$index]);
  9220. break;
  9221. }
  9222. }
  9223. }
  9224. return $this->dispatcher->removeListener($eventName, $listener);
  9225. }
  9226. public function removeSubscriber(EventSubscriberInterface $subscriber)
  9227. {
  9228. return $this->dispatcher->removeSubscriber($subscriber);
  9229. }
  9230. public function getListeners(?string $eventName = null)
  9231. {
  9232. return $this->dispatcher->getListeners($eventName);
  9233. }
  9234. public function getListenerPriority(string $eventName, $listener)
  9235. {
  9236. if (isset($this->wrappedListeners[$eventName])) {
  9237. foreach ($this->wrappedListeners[$eventName] as $wrappedListener) {
  9238. if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
  9239. return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
  9240. }
  9241. }
  9242. }
  9243. return $this->dispatcher->getListenerPriority($eventName, $listener);
  9244. }
  9245. public function hasListeners(?string $eventName = null)
  9246. {
  9247. return $this->dispatcher->hasListeners($eventName);
  9248. }
  9249. public function dispatch(object $event, ?string $eventName = null): object
  9250. {
  9251. $eventName = $eventName ?? \get_class($event);
  9252. if (null === $this->callStack) {
  9253. $this->callStack = new \SplObjectStorage();
  9254. }
  9255. $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';
  9256. if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  9257. $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
  9258. }
  9259. $this->preProcess($eventName);
  9260. try {
  9261. $this->beforeDispatch($eventName, $event);
  9262. try {
  9263. $e = $this->stopwatch->start($eventName, 'section');
  9264. try {
  9265. $this->dispatcher->dispatch($event, $eventName);
  9266. } finally {
  9267. if ($e->isStarted()) {
  9268. $e->stop();
  9269. }
  9270. }
  9271. } finally {
  9272. $this->afterDispatch($eventName, $event);
  9273. }
  9274. } finally {
  9275. $this->currentRequestHash = $currentRequestHash;
  9276. $this->postProcess($eventName);
  9277. }
  9278. return $event;
  9279. }
  9280. public function getCalledListeners(?Request $request = null)
  9281. {
  9282. if (null === $this->callStack) {
  9283. return [];
  9284. }
  9285. $hash = $request ? spl_object_hash($request) : null;
  9286. $called = [];
  9287. foreach ($this->callStack as $listener) {
  9288. [$eventName, $requestHash] = $this->callStack->getInfo();
  9289. if (null === $hash || $hash === $requestHash) {
  9290. $called[] = $listener->getInfo($eventName);
  9291. }
  9292. }
  9293. return $called;
  9294. }
  9295. public function getNotCalledListeners(?Request $request = null)
  9296. {
  9297. try {
  9298. $allListeners = $this->getListeners();
  9299. } catch (\Exception $e) {
  9300. if (null !== $this->logger) {
  9301. $this->logger->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]);
  9302. }
  9303. return [];
  9304. }
  9305. $hash = $request ? spl_object_hash($request) : null;
  9306. $calledListeners = [];
  9307. if (null !== $this->callStack) {
  9308. foreach ($this->callStack as $calledListener) {
  9309. [, $requestHash] = $this->callStack->getInfo();
  9310. if (null === $hash || $hash === $requestHash) {
  9311. $calledListeners[] = $calledListener->getWrappedListener();
  9312. }
  9313. }
  9314. }
  9315. $notCalled = [];
  9316. foreach ($allListeners as $eventName => $listeners) {
  9317. foreach ($listeners as $listener) {
  9318. if (!\in_array($listener, $calledListeners, true)) {
  9319. if (!$listener instanceof WrappedListener) {
  9320. $listener = new WrappedListener($listener, null, $this->stopwatch, $this);
  9321. }
  9322. $notCalled[] = $listener->getInfo($eventName);
  9323. }
  9324. }
  9325. }
  9326. uasort($notCalled, [$this, 'sortNotCalledListeners']);
  9327. return $notCalled;
  9328. }
  9329. public function getOrphanedEvents(?Request $request = null): array
  9330. {
  9331. if ($request) {
  9332. return $this->orphanedEvents[spl_object_hash($request)] ?? [];
  9333. }
  9334. if (!$this->orphanedEvents) {
  9335. return [];
  9336. }
  9337. return array_merge(...array_values($this->orphanedEvents));
  9338. }
  9339. public function reset()
  9340. {
  9341. $this->callStack = null;
  9342. $this->orphanedEvents = [];
  9343. $this->currentRequestHash = '';
  9344. }
  9345. public function __call(string $method, array $arguments)
  9346. {
  9347. return $this->dispatcher->{$method}(...$arguments);
  9348. }
  9349. protected function beforeDispatch(string $eventName, object $event)
  9350. {
  9351. }
  9352. protected function afterDispatch(string $eventName, object $event)
  9353. {
  9354. }
  9355. private function preProcess(string $eventName): void
  9356. {
  9357. if (!$this->dispatcher->hasListeners($eventName)) {
  9358. $this->orphanedEvents[$this->currentRequestHash][] = $eventName;
  9359. return;
  9360. }
  9361. foreach ($this->dispatcher->getListeners($eventName) as $listener) {
  9362. $priority = $this->getListenerPriority($eventName, $listener);
  9363. $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this);
  9364. $this->wrappedListeners[$eventName][] = $wrappedListener;
  9365. $this->dispatcher->removeListener($eventName, $listener);
  9366. $this->dispatcher->addListener($eventName, $wrappedListener, $priority);
  9367. $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]);
  9368. }
  9369. }
  9370. private function postProcess(string $eventName): void
  9371. {
  9372. unset($this->wrappedListeners[$eventName]);
  9373. $skipped = false;
  9374. foreach ($this->dispatcher->getListeners($eventName) as $listener) {
  9375. if (!$listener instanceof WrappedListener) {
  9376. continue;
  9377. }
  9378. $priority = $this->getListenerPriority($eventName, $listener);
  9379. $this->dispatcher->removeListener($eventName, $listener);
  9380. $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
  9381. if (null !== $this->logger) {
  9382. $context = ['event' => $eventName, 'listener' => $listener->getPretty()];
  9383. }
  9384. if ($listener->wasCalled()) {
  9385. if (null !== $this->logger) {
  9386. $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
  9387. }
  9388. } else {
  9389. $this->callStack->detach($listener);
  9390. }
  9391. if (null !== $this->logger && $skipped) {
  9392. $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
  9393. }
  9394. if ($listener->stoppedPropagation()) {
  9395. if (null !== $this->logger) {
  9396. $this->logger->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context);
  9397. }
  9398. $skipped = true;
  9399. }
  9400. }
  9401. }
  9402. private function sortNotCalledListeners(array $a, array $b)
  9403. {
  9404. if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
  9405. return $cmp;
  9406. }
  9407. if (\is_int($a['priority']) && !\is_int($b['priority'])) {
  9408. return 1;
  9409. }
  9410. if (!\is_int($a['priority']) && \is_int($b['priority'])) {
  9411. return -1;
  9412. }
  9413. if ($a['priority'] === $b['priority']) {
  9414. return 0;
  9415. }
  9416. if ($a['priority'] > $b['priority']) {
  9417. return -1;
  9418. }
  9419. return 1;
  9420. }
  9421. }
  9422. <?php
  9423. namespace Symfony\Component\EventDispatcher\Debug;
  9424. use Psr\EventDispatcher\StoppableEventInterface;
  9425. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  9426. use Symfony\Component\Stopwatch\Stopwatch;
  9427. use Symfony\Component\VarDumper\Caster\ClassStub;
  9428. final class WrappedListener
  9429. {
  9430. private $listener;
  9431. private $optimizedListener;
  9432. private $name;
  9433. private $called;
  9434. private $stoppedPropagation;
  9435. private $stopwatch;
  9436. private $dispatcher;
  9437. private $pretty;
  9438. private $stub;
  9439. private $priority;
  9440. private static $hasClassStub;
  9441. public function __construct($listener, ?string $name, Stopwatch $stopwatch, ?EventDispatcherInterface $dispatcher = null)
  9442. {
  9443. $this->listener = $listener;
  9444. $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null);
  9445. $this->stopwatch = $stopwatch;
  9446. $this->dispatcher = $dispatcher;
  9447. $this->called = false;
  9448. $this->stoppedPropagation = false;
  9449. if (\is_array($listener)) {
  9450. $this->name = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0];
  9451. $this->pretty = $this->name.'::'.$listener[1];
  9452. } elseif ($listener instanceof \Closure) {
  9453. $r = new \ReflectionFunction($listener);
  9454. if (str_contains($r->name, '{closure')) {
  9455. $this->pretty = $this->name = 'closure';
  9456. } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
  9457. $this->name = $class->name;
  9458. $this->pretty = $this->name.'::'.$r->name;
  9459. } else {
  9460. $this->pretty = $this->name = $r->name;
  9461. }
  9462. } elseif (\is_string($listener)) {
  9463. $this->pretty = $this->name = $listener;
  9464. } else {
  9465. $this->name = get_debug_type($listener);
  9466. $this->pretty = $this->name.'::__invoke';
  9467. }
  9468. if (null !== $name) {
  9469. $this->name = $name;
  9470. }
  9471. if (null === self::$hasClassStub) {
  9472. self::$hasClassStub = class_exists(ClassStub::class);
  9473. }
  9474. }
  9475. public function getWrappedListener()
  9476. {
  9477. return $this->listener;
  9478. }
  9479. public function wasCalled(): bool
  9480. {
  9481. return $this->called;
  9482. }
  9483. public function stoppedPropagation(): bool
  9484. {
  9485. return $this->stoppedPropagation;
  9486. }
  9487. public function getPretty(): string
  9488. {
  9489. return $this->pretty;
  9490. }
  9491. public function getInfo(string $eventName): array
  9492. {
  9493. if (null === $this->stub) {
  9494. $this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
  9495. }
  9496. return [
  9497. 'event' => $eventName,
  9498. 'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null),
  9499. 'pretty' => $this->pretty,
  9500. 'stub' => $this->stub,
  9501. ];
  9502. }
  9503. public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void
  9504. {
  9505. $dispatcher = $this->dispatcher ?: $dispatcher;
  9506. $this->called = true;
  9507. $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener);
  9508. $e = $this->stopwatch->start($this->name, 'event_listener');
  9509. try {
  9510. ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);
  9511. } finally {
  9512. if ($e->isStarted()) {
  9513. $e->stop();
  9514. }
  9515. }
  9516. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  9517. $this->stoppedPropagation = true;
  9518. }
  9519. }
  9520. }
  9521. <?php
  9522. namespace Symfony\Component\Filesystem;
  9523. use Symfony\Component\Filesystem\Exception\FileNotFoundException;
  9524. use Symfony\Component\Filesystem\Exception\InvalidArgumentException;
  9525. use Symfony\Component\Filesystem\Exception\IOException;
  9526. class Filesystem
  9527. {
  9528. private static $lastError;
  9529. public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false)
  9530. {
  9531. $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
  9532. if ($originIsLocal && !is_file($originFile)) {
  9533. throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
  9534. }
  9535. $this->mkdir(\dirname($targetFile));
  9536. $doCopy = true;
  9537. if (!$overwriteNewerFiles && !parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) {
  9538. $doCopy = filemtime($originFile) > filemtime($targetFile);
  9539. }
  9540. if ($doCopy) {
  9541. if (!$source = self::box('fopen', $originFile, 'r')) {
  9542. throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile);
  9543. }
  9544. if (!$target = self::box('fopen', $targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) {
  9545. throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile);
  9546. }
  9547. $bytesCopied = stream_copy_to_stream($source, $target);
  9548. fclose($source);
  9549. fclose($target);
  9550. unset($source, $target);
  9551. if (!is_file($targetFile)) {
  9552. throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
  9553. }
  9554. if ($originIsLocal) {
  9555. self::box('chmod', $targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
  9556. self::box('touch', $targetFile, filemtime($originFile));
  9557. if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
  9558. throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
  9559. }
  9560. }
  9561. }
  9562. }
  9563. public function mkdir($dirs, int $mode = 0777)
  9564. {
  9565. foreach ($this->toIterable($dirs) as $dir) {
  9566. if (is_dir($dir)) {
  9567. continue;
  9568. }
  9569. if (!self::box('mkdir', $dir, $mode, true) && !is_dir($dir)) {
  9570. throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir);
  9571. }
  9572. }
  9573. }
  9574. public function exists($files)
  9575. {
  9576. $maxPathLength = \PHP_MAXPATHLEN - 2;
  9577. foreach ($this->toIterable($files) as $file) {
  9578. if (\strlen($file) > $maxPathLength) {
  9579. throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
  9580. }
  9581. if (!file_exists($file)) {
  9582. return false;
  9583. }
  9584. }
  9585. return true;
  9586. }
  9587. public function touch($files, ?int $time = null, ?int $atime = null)
  9588. {
  9589. foreach ($this->toIterable($files) as $file) {
  9590. if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) {
  9591. throw new IOException(sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file);
  9592. }
  9593. }
  9594. }
  9595. public function remove($files)
  9596. {
  9597. if ($files instanceof \Traversable) {
  9598. $files = iterator_to_array($files, false);
  9599. } elseif (!\is_array($files)) {
  9600. $files = [$files];
  9601. }
  9602. self::doRemove($files, false);
  9603. }
  9604. private static function doRemove(array $files, bool $isRecursive): void
  9605. {
  9606. $files = array_reverse($files);
  9607. foreach ($files as $file) {
  9608. if (is_link($file)) {
  9609. if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
  9610. throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError);
  9611. }
  9612. } elseif (is_dir($file)) {
  9613. if (!$isRecursive) {
  9614. $tmpName = \dirname(realpath($file)).'/.!'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-!'));
  9615. if (file_exists($tmpName)) {
  9616. try {
  9617. self::doRemove([$tmpName], true);
  9618. } catch (IOException $e) {
  9619. }
  9620. }
  9621. if (!file_exists($tmpName) && self::box('rename', $file, $tmpName)) {
  9622. $origFile = $file;
  9623. $file = $tmpName;
  9624. } else {
  9625. $origFile = null;
  9626. }
  9627. }
  9628. $files = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS);
  9629. self::doRemove(iterator_to_array($files, true), true);
  9630. if (!self::box('rmdir', $file) && file_exists($file) && !$isRecursive) {
  9631. $lastError = self::$lastError;
  9632. if (null !== $origFile && self::box('rename', $file, $origFile)) {
  9633. $file = $origFile;
  9634. }
  9635. throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError);
  9636. }
  9637. } elseif (!self::box('unlink', $file) && ((self::$lastError && str_contains(self::$lastError, 'Permission denied')) || file_exists($file))) {
  9638. throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError);
  9639. }
  9640. }
  9641. }
  9642. public function chmod($files, int $mode, int $umask = 0000, bool $recursive = false)
  9643. {
  9644. foreach ($this->toIterable($files) as $file) {
  9645. if ((\PHP_VERSION_ID < 80000 || \is_int($mode)) && !self::box('chmod', $file, $mode & ~$umask)) {
  9646. throw new IOException(sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file);
  9647. }
  9648. if ($recursive && is_dir($file) && !is_link($file)) {
  9649. $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
  9650. }
  9651. }
  9652. }
  9653. public function chown($files, $user, bool $recursive = false)
  9654. {
  9655. foreach ($this->toIterable($files) as $file) {
  9656. if ($recursive && is_dir($file) && !is_link($file)) {
  9657. $this->chown(new \FilesystemIterator($file), $user, true);
  9658. }
  9659. if (is_link($file) && \function_exists('lchown')) {
  9660. if (!self::box('lchown', $file, $user)) {
  9661. throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file);
  9662. }
  9663. } else {
  9664. if (!self::box('chown', $file, $user)) {
  9665. throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file);
  9666. }
  9667. }
  9668. }
  9669. }
  9670. public function chgrp($files, $group, bool $recursive = false)
  9671. {
  9672. foreach ($this->toIterable($files) as $file) {
  9673. if ($recursive && is_dir($file) && !is_link($file)) {
  9674. $this->chgrp(new \FilesystemIterator($file), $group, true);
  9675. }
  9676. if (is_link($file) && \function_exists('lchgrp')) {
  9677. if (!self::box('lchgrp', $file, $group)) {
  9678. throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file);
  9679. }
  9680. } else {
  9681. if (!self::box('chgrp', $file, $group)) {
  9682. throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file);
  9683. }
  9684. }
  9685. }
  9686. }
  9687. public function rename(string $origin, string $target, bool $overwrite = false)
  9688. {
  9689. if (!$overwrite && $this->isReadable($target)) {
  9690. throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
  9691. }
  9692. if (!self::box('rename', $origin, $target)) {
  9693. if (is_dir($origin)) {
  9694. $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]);
  9695. $this->remove($origin);
  9696. return;
  9697. }
  9698. throw new IOException(sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target);
  9699. }
  9700. }
  9701. private function isReadable(string $filename): bool
  9702. {
  9703. $maxPathLength = \PHP_MAXPATHLEN - 2;
  9704. if (\strlen($filename) > $maxPathLength) {
  9705. throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
  9706. }
  9707. return is_readable($filename);
  9708. }
  9709. public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false)
  9710. {
  9711. self::assertFunctionExists('symlink');
  9712. if ('\\' === \DIRECTORY_SEPARATOR) {
  9713. $originDir = strtr($originDir, '/', '\\');
  9714. $targetDir = strtr($targetDir, '/', '\\');
  9715. if ($copyOnWindows) {
  9716. $this->mirror($originDir, $targetDir);
  9717. return;
  9718. }
  9719. }
  9720. $this->mkdir(\dirname($targetDir));
  9721. if (is_link($targetDir)) {
  9722. if (readlink($targetDir) === $originDir) {
  9723. return;
  9724. }
  9725. $this->remove($targetDir);
  9726. }
  9727. if (!self::box('symlink', $originDir, $targetDir)) {
  9728. $this->linkException($originDir, $targetDir, 'symbolic');
  9729. }
  9730. }
  9731. public function hardlink(string $originFile, $targetFiles)
  9732. {
  9733. self::assertFunctionExists('link');
  9734. if (!$this->exists($originFile)) {
  9735. throw new FileNotFoundException(null, 0, null, $originFile);
  9736. }
  9737. if (!is_file($originFile)) {
  9738. throw new FileNotFoundException(sprintf('Origin file "%s" is not a file.', $originFile));
  9739. }
  9740. foreach ($this->toIterable($targetFiles) as $targetFile) {
  9741. if (is_file($targetFile)) {
  9742. if (fileinode($originFile) === fileinode($targetFile)) {
  9743. continue;
  9744. }
  9745. $this->remove($targetFile);
  9746. }
  9747. if (!self::box('link', $originFile, $targetFile)) {
  9748. $this->linkException($originFile, $targetFile, 'hard');
  9749. }
  9750. }
  9751. }
  9752. private function linkException(string $origin, string $target, string $linkType)
  9753. {
  9754. if (self::$lastError) {
  9755. if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) {
  9756. throw new IOException(sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
  9757. }
  9758. }
  9759. throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target);
  9760. }
  9761. public function readlink(string $path, bool $canonicalize = false)
  9762. {
  9763. if (!$canonicalize && !is_link($path)) {
  9764. return null;
  9765. }
  9766. if ($canonicalize) {
  9767. if (!$this->exists($path)) {
  9768. return null;
  9769. }
  9770. if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70410) {
  9771. $path = readlink($path);
  9772. }
  9773. return realpath($path);
  9774. }
  9775. if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) {
  9776. return realpath($path);
  9777. }
  9778. return readlink($path);
  9779. }
  9780. public function makePathRelative(string $endPath, string $startPath)
  9781. {
  9782. if (!$this->isAbsolutePath($startPath)) {
  9783. throw new InvalidArgumentException(sprintf('The start path "%s" is not absolute.', $startPath));
  9784. }
  9785. if (!$this->isAbsolutePath($endPath)) {
  9786. throw new InvalidArgumentException(sprintf('The end path "%s" is not absolute.', $endPath));
  9787. }
  9788. if ('\\' === \DIRECTORY_SEPARATOR) {
  9789. $endPath = str_replace('\\', '/', $endPath);
  9790. $startPath = str_replace('\\', '/', $startPath);
  9791. }
  9792. $splitDriveLetter = function ($path) {
  9793. return (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0]))
  9794. ? [substr($path, 2), strtoupper($path[0])]
  9795. : [$path, null];
  9796. };
  9797. $splitPath = function ($path) {
  9798. $result = [];
  9799. foreach (explode('/', trim($path, '/')) as $segment) {
  9800. if ('..' === $segment) {
  9801. array_pop($result);
  9802. } elseif ('.' !== $segment && '' !== $segment) {
  9803. $result[] = $segment;
  9804. }
  9805. }
  9806. return $result;
  9807. };
  9808. [$endPath, $endDriveLetter] = $splitDriveLetter($endPath);
  9809. [$startPath, $startDriveLetter] = $splitDriveLetter($startPath);
  9810. $startPathArr = $splitPath($startPath);
  9811. $endPathArr = $splitPath($endPath);
  9812. if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
  9813. return $endDriveLetter.':/'.($endPathArr ? implode('/', $endPathArr).'/' : '');
  9814. }
  9815. $index = 0;
  9816. while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
  9817. ++$index;
  9818. }
  9819. if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
  9820. $depth = 0;
  9821. } else {
  9822. $depth = \count($startPathArr) - $index;
  9823. }
  9824. $traverser = str_repeat('../', $depth);
  9825. $endPathRemainder = implode('/', \array_slice($endPathArr, $index));
  9826. $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
  9827. return '' === $relativePath ? './' : $relativePath;
  9828. }
  9829. public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = [])
  9830. {
  9831. $targetDir = rtrim($targetDir, '/\\');
  9832. $originDir = rtrim($originDir, '/\\');
  9833. $originDirLen = \strlen($originDir);
  9834. if (!$this->exists($originDir)) {
  9835. throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir);
  9836. }
  9837. if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
  9838. $deleteIterator = $iterator;
  9839. if (null === $deleteIterator) {
  9840. $flags = \FilesystemIterator::SKIP_DOTS;
  9841. $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
  9842. }
  9843. $targetDirLen = \strlen($targetDir);
  9844. foreach ($deleteIterator as $file) {
  9845. $origin = $originDir.substr($file->getPathname(), $targetDirLen);
  9846. if (!$this->exists($origin)) {
  9847. $this->remove($file);
  9848. }
  9849. }
  9850. }
  9851. $copyOnWindows = $options['copy_on_windows'] ?? false;
  9852. if (null === $iterator) {
  9853. $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
  9854. $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
  9855. }
  9856. $this->mkdir($targetDir);
  9857. $filesCreatedWhileMirroring = [];
  9858. foreach ($iterator as $file) {
  9859. if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) {
  9860. continue;
  9861. }
  9862. $target = $targetDir.substr($file->getPathname(), $originDirLen);
  9863. $filesCreatedWhileMirroring[$target] = true;
  9864. if (!$copyOnWindows && is_link($file)) {
  9865. $this->symlink($file->getLinkTarget(), $target);
  9866. } elseif (is_dir($file)) {
  9867. $this->mkdir($target);
  9868. } elseif (is_file($file)) {
  9869. $this->copy($file, $target, $options['override'] ?? false);
  9870. } else {
  9871. throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
  9872. }
  9873. }
  9874. }
  9875. public function isAbsolutePath(string $file)
  9876. {
  9877. return '' !== $file && (strspn($file, '/\\', 0, 1)
  9878. || (\strlen($file) > 3 && ctype_alpha($file[0])
  9879. && ':' === $file[1]
  9880. && strspn($file, '/\\', 2, 1)
  9881. )
  9882. || null !== parse_url($file, \PHP_URL_SCHEME)
  9883. );
  9884. }
  9885. public function tempnam(string $dir, string $prefix)
  9886. {
  9887. $suffix = \func_num_args() > 2 ? func_get_arg(2) : '';
  9888. [$scheme, $hierarchy] = $this->getSchemeAndHierarchy($dir);
  9889. if ((null === $scheme || 'file' === $scheme || 'gs' === $scheme) && '' === $suffix) {
  9890. if ($tmpFile = self::box('tempnam', $hierarchy, $prefix)) {
  9891. if (null !== $scheme && 'gs' !== $scheme) {
  9892. return $scheme.'://'.$tmpFile;
  9893. }
  9894. return $tmpFile;
  9895. }
  9896. throw new IOException('A temporary file could not be created: '.self::$lastError);
  9897. }
  9898. for ($i = 0; $i < 10; ++$i) {
  9899. $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true).$suffix;
  9900. if (!$handle = self::box('fopen', $tmpFile, 'x+')) {
  9901. continue;
  9902. }
  9903. self::box('fclose', $handle);
  9904. return $tmpFile;
  9905. }
  9906. throw new IOException('A temporary file could not be created: '.self::$lastError);
  9907. }
  9908. public function dumpFile(string $filename, $content)
  9909. {
  9910. if (\is_array($content)) {
  9911. throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__));
  9912. }
  9913. $dir = \dirname($filename);
  9914. if (is_link($filename) && $linkTarget = $this->readlink($filename)) {
  9915. $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content);
  9916. return;
  9917. }
  9918. if (!is_dir($dir)) {
  9919. $this->mkdir($dir);
  9920. }
  9921. $tmpFile = $this->tempnam($dir, basename($filename));
  9922. try {
  9923. if (false === self::box('file_put_contents', $tmpFile, $content)) {
  9924. throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename);
  9925. }
  9926. self::box('chmod', $tmpFile, self::box('fileperms', $filename) ?: 0666 & ~umask());
  9927. $this->rename($tmpFile, $filename, true);
  9928. } finally {
  9929. if (file_exists($tmpFile)) {
  9930. if ('\\' === \DIRECTORY_SEPARATOR && !is_writable($tmpFile)) {
  9931. self::box('chmod', $tmpFile, self::box('fileperms', $tmpFile) | 0200);
  9932. }
  9933. self::box('unlink', $tmpFile);
  9934. }
  9935. }
  9936. }
  9937. public function appendToFile(string $filename, $content)
  9938. {
  9939. if (\is_array($content)) {
  9940. throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__));
  9941. }
  9942. $dir = \dirname($filename);
  9943. if (!is_dir($dir)) {
  9944. $this->mkdir($dir);
  9945. }
  9946. $lock = \func_num_args() > 2 && func_get_arg(2);
  9947. if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) {
  9948. throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename);
  9949. }
  9950. }
  9951. private function toIterable($files): iterable
  9952. {
  9953. return is_iterable($files) ? $files : [$files];
  9954. }
  9955. private function getSchemeAndHierarchy(string $filename): array
  9956. {
  9957. $components = explode('://', $filename, 2);
  9958. return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]];
  9959. }
  9960. private static function assertFunctionExists(string $func): void
  9961. {
  9962. if (!\function_exists($func)) {
  9963. throw new IOException(sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func));
  9964. }
  9965. }
  9966. private static function box(string $func, ...$args)
  9967. {
  9968. self::assertFunctionExists($func);
  9969. self::$lastError = null;
  9970. set_error_handler(__CLASS__.'::handleError');
  9971. try {
  9972. return $func(...$args);
  9973. } finally {
  9974. restore_error_handler();
  9975. }
  9976. }
  9977. public static function handleError(int $type, string $msg)
  9978. {
  9979. self::$lastError = $msg;
  9980. }
  9981. }
  9982. <?php
  9983. namespace Symfony\Component\Filesystem;
  9984. use Symfony\Component\Filesystem\Exception\InvalidArgumentException;
  9985. use Symfony\Component\Filesystem\Exception\RuntimeException;
  9986. final class Path
  9987. {
  9988. private const CLEANUP_THRESHOLD = 1250;
  9989. private const CLEANUP_SIZE = 1000;
  9990. private static $buffer = [];
  9991. private static $bufferSize = 0;
  9992. public static function canonicalize(string $path): string
  9993. {
  9994. if ('' === $path) {
  9995. return '';
  9996. }
  9997. if (isset(self::$buffer[$path])) {
  9998. return self::$buffer[$path];
  9999. }
  10000. if ('~' === $path[0]) {
  10001. $path = self::getHomeDirectory().substr($path, 1);
  10002. }
  10003. $path = self::normalize($path);
  10004. [$root, $pathWithoutRoot] = self::split($path);
  10005. $canonicalParts = self::findCanonicalParts($root, $pathWithoutRoot);
  10006. self::$buffer[$path] = $canonicalPath = $root.implode('/', $canonicalParts);
  10007. ++self::$bufferSize;
  10008. if (self::$bufferSize > self::CLEANUP_THRESHOLD) {
  10009. self::$buffer = \array_slice(self::$buffer, -self::CLEANUP_SIZE, null, true);
  10010. self::$bufferSize = self::CLEANUP_SIZE;
  10011. }
  10012. return $canonicalPath;
  10013. }
  10014. public static function normalize(string $path): string
  10015. {
  10016. return str_replace('\\', '/', $path);
  10017. }
  10018. public static function getDirectory(string $path): string
  10019. {
  10020. if ('' === $path) {
  10021. return '';
  10022. }
  10023. $path = self::canonicalize($path);
  10024. if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
  10025. $scheme = substr($path, 0, $schemeSeparatorPosition + 3);
  10026. $path = substr($path, $schemeSeparatorPosition + 3);
  10027. } else {
  10028. $scheme = '';
  10029. }
  10030. if (false === $dirSeparatorPosition = strrpos($path, '/')) {
  10031. return '';
  10032. }
  10033. if (0 === $dirSeparatorPosition) {
  10034. return $scheme.'/';
  10035. }
  10036. if (2 === $dirSeparatorPosition && ctype_alpha($path[0]) && ':' === $path[1]) {
  10037. return $scheme.substr($path, 0, 3);
  10038. }
  10039. return $scheme.substr($path, 0, $dirSeparatorPosition);
  10040. }
  10041. public static function getHomeDirectory(): string
  10042. {
  10043. if (getenv('HOME')) {
  10044. return self::canonicalize(getenv('HOME'));
  10045. }
  10046. if (getenv('HOMEDRIVE') && getenv('HOMEPATH')) {
  10047. return self::canonicalize(getenv('HOMEDRIVE').getenv('HOMEPATH'));
  10048. }
  10049. throw new RuntimeException("Cannot find the home directory path: Your environment or operating system isn't supported.");
  10050. }
  10051. public static function getRoot(string $path): string
  10052. {
  10053. if ('' === $path) {
  10054. return '';
  10055. }
  10056. if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
  10057. $scheme = substr($path, 0, $schemeSeparatorPosition + 3);
  10058. $path = substr($path, $schemeSeparatorPosition + 3);
  10059. } else {
  10060. $scheme = '';
  10061. }
  10062. $firstCharacter = $path[0];
  10063. if ('/' === $firstCharacter || '\\' === $firstCharacter) {
  10064. return $scheme.'/';
  10065. }
  10066. $length = \strlen($path);
  10067. if ($length > 1 && ':' === $path[1] && ctype_alpha($firstCharacter)) {
  10068. if (2 === $length) {
  10069. return $scheme.$path.'/';
  10070. }
  10071. if ('/' === $path[2] || '\\' === $path[2]) {
  10072. return $scheme.$firstCharacter.$path[1].'/';
  10073. }
  10074. }
  10075. return '';
  10076. }
  10077. public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string
  10078. {
  10079. if ('' === $path) {
  10080. return '';
  10081. }
  10082. if (null !== $extension) {
  10083. return rtrim(basename($path, $extension), '.');
  10084. }
  10085. return pathinfo($path, \PATHINFO_FILENAME);
  10086. }
  10087. public static function getExtension(string $path, bool $forceLowerCase = false): string
  10088. {
  10089. if ('' === $path) {
  10090. return '';
  10091. }
  10092. $extension = pathinfo($path, \PATHINFO_EXTENSION);
  10093. if ($forceLowerCase) {
  10094. $extension = self::toLower($extension);
  10095. }
  10096. return $extension;
  10097. }
  10098. public static function hasExtension(string $path, $extensions = null, bool $ignoreCase = false): bool
  10099. {
  10100. if ('' === $path) {
  10101. return false;
  10102. }
  10103. $actualExtension = self::getExtension($path, $ignoreCase);
  10104. if ([] === $extensions || null === $extensions) {
  10105. return '' !== $actualExtension;
  10106. }
  10107. if (\is_string($extensions)) {
  10108. $extensions = [$extensions];
  10109. }
  10110. foreach ($extensions as $key => $extension) {
  10111. if ($ignoreCase) {
  10112. $extension = self::toLower($extension);
  10113. }
  10114. $extensions[$key] = ltrim($extension, '.');
  10115. }
  10116. return \in_array($actualExtension, $extensions, true);
  10117. }
  10118. public static function changeExtension(string $path, string $extension): string
  10119. {
  10120. if ('' === $path) {
  10121. return '';
  10122. }
  10123. $actualExtension = self::getExtension($path);
  10124. $extension = ltrim($extension, '.');
  10125. if ('/' === substr($path, -1)) {
  10126. return $path;
  10127. }
  10128. if (empty($actualExtension)) {
  10129. return $path.('.' === substr($path, -1) ? '' : '.').$extension;
  10130. }
  10131. return substr($path, 0, -\strlen($actualExtension)).$extension;
  10132. }
  10133. public static function isAbsolute(string $path): bool
  10134. {
  10135. if ('' === $path) {
  10136. return false;
  10137. }
  10138. if (false !== ($schemeSeparatorPosition = strpos($path, '://')) && 1 !== $schemeSeparatorPosition) {
  10139. $path = substr($path, $schemeSeparatorPosition + 3);
  10140. }
  10141. $firstCharacter = $path[0];
  10142. if ('/' === $firstCharacter || '\\' === $firstCharacter) {
  10143. return true;
  10144. }
  10145. if (\strlen($path) > 1 && ctype_alpha($firstCharacter) && ':' === $path[1]) {
  10146. if (2 === \strlen($path)) {
  10147. return true;
  10148. }
  10149. if ('/' === $path[2] || '\\' === $path[2]) {
  10150. return true;
  10151. }
  10152. }
  10153. return false;
  10154. }
  10155. public static function isRelative(string $path): bool
  10156. {
  10157. return !self::isAbsolute($path);
  10158. }
  10159. public static function makeAbsolute(string $path, string $basePath): string
  10160. {
  10161. if ('' === $basePath) {
  10162. throw new InvalidArgumentException(sprintf('The base path must be a non-empty string. Got: "%s".', $basePath));
  10163. }
  10164. if (!self::isAbsolute($basePath)) {
  10165. throw new InvalidArgumentException(sprintf('The base path "%s" is not an absolute path.', $basePath));
  10166. }
  10167. if (self::isAbsolute($path)) {
  10168. return self::canonicalize($path);
  10169. }
  10170. if (false !== $schemeSeparatorPosition = strpos($basePath, '://')) {
  10171. $scheme = substr($basePath, 0, $schemeSeparatorPosition + 3);
  10172. $basePath = substr($basePath, $schemeSeparatorPosition + 3);
  10173. } else {
  10174. $scheme = '';
  10175. }
  10176. return $scheme.self::canonicalize(rtrim($basePath, '/\\').'/'.$path);
  10177. }
  10178. public static function makeRelative(string $path, string $basePath): string
  10179. {
  10180. $path = self::canonicalize($path);
  10181. $basePath = self::canonicalize($basePath);
  10182. [$root, $relativePath] = self::split($path);
  10183. [$baseRoot, $relativeBasePath] = self::split($basePath);
  10184. if ('' === $root && '' !== $baseRoot) {
  10185. if ('' === $relativeBasePath) {
  10186. $relativePath = ltrim($relativePath, './\\');
  10187. }
  10188. return $relativePath;
  10189. }
  10190. if ('' !== $root && '' === $baseRoot) {
  10191. throw new InvalidArgumentException(sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath));
  10192. }
  10193. if ($baseRoot && $root !== $baseRoot) {
  10194. throw new InvalidArgumentException(sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot));
  10195. }
  10196. if ('' === $relativeBasePath) {
  10197. return $relativePath;
  10198. }
  10199. $parts = explode('/', $relativePath);
  10200. $baseParts = explode('/', $relativeBasePath);
  10201. $dotDotPrefix = '';
  10202. $match = true;
  10203. foreach ($baseParts as $index => $basePart) {
  10204. if ($match && isset($parts[$index]) && $basePart === $parts[$index]) {
  10205. unset($parts[$index]);
  10206. continue;
  10207. }
  10208. $match = false;
  10209. $dotDotPrefix .= '../';
  10210. }
  10211. return rtrim($dotDotPrefix.implode('/', $parts), '/');
  10212. }
  10213. public static function isLocal(string $path): bool
  10214. {
  10215. return '' !== $path && false === strpos($path, '://');
  10216. }
  10217. public static function getLongestCommonBasePath(string ...$paths): ?string
  10218. {
  10219. [$bpRoot, $basePath] = self::split(self::canonicalize(reset($paths)));
  10220. for (next($paths); null !== key($paths) && '' !== $basePath; next($paths)) {
  10221. [$root, $path] = self::split(self::canonicalize(current($paths)));
  10222. if ($root !== $bpRoot) {
  10223. return null;
  10224. }
  10225. while (true) {
  10226. if ('.' === $basePath) {
  10227. $basePath = '';
  10228. continue 2;
  10229. }
  10230. if (0 === strpos($path.'/', $basePath.'/')) {
  10231. continue 2;
  10232. }
  10233. $basePath = \dirname($basePath);
  10234. }
  10235. }
  10236. return $bpRoot.$basePath;
  10237. }
  10238. public static function join(string ...$paths): string
  10239. {
  10240. $finalPath = null;
  10241. $wasScheme = false;
  10242. foreach ($paths as $path) {
  10243. if ('' === $path) {
  10244. continue;
  10245. }
  10246. if (null === $finalPath) {
  10247. $finalPath = $path;
  10248. $wasScheme = (false !== strpos($path, '://'));
  10249. continue;
  10250. }
  10251. if (!\in_array(substr($finalPath, -1), ['/', '\\'])) {
  10252. $finalPath .= '/';
  10253. }
  10254. $finalPath .= $wasScheme ? $path : ltrim($path, '/');
  10255. $wasScheme = false;
  10256. }
  10257. if (null === $finalPath) {
  10258. return '';
  10259. }
  10260. return self::canonicalize($finalPath);
  10261. }
  10262. public static function isBasePath(string $basePath, string $ofPath): bool
  10263. {
  10264. $basePath = self::canonicalize($basePath);
  10265. $ofPath = self::canonicalize($ofPath);
  10266. return 0 === strpos($ofPath.'/', rtrim($basePath, '/').'/');
  10267. }
  10268. private static function findCanonicalParts(string $root, string $pathWithoutRoot): array
  10269. {
  10270. $parts = explode('/', $pathWithoutRoot);
  10271. $canonicalParts = [];
  10272. foreach ($parts as $part) {
  10273. if ('.' === $part || '' === $part) {
  10274. continue;
  10275. }
  10276. if ('..' === $part && \count($canonicalParts) > 0 && '..' !== $canonicalParts[\count($canonicalParts) - 1]) {
  10277. array_pop($canonicalParts);
  10278. continue;
  10279. }
  10280. if ('..' !== $part || '' === $root) {
  10281. $canonicalParts[] = $part;
  10282. }
  10283. }
  10284. return $canonicalParts;
  10285. }
  10286. private static function split(string $path): array
  10287. {
  10288. if ('' === $path) {
  10289. return ['', ''];
  10290. }
  10291. if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
  10292. $root = substr($path, 0, $schemeSeparatorPosition + 3);
  10293. $path = substr($path, $schemeSeparatorPosition + 3);
  10294. } else {
  10295. $root = '';
  10296. }
  10297. $length = \strlen($path);
  10298. if (0 === strpos($path, '/')) {
  10299. $root .= '/';
  10300. $path = $length > 1 ? substr($path, 1) : '';
  10301. } elseif ($length > 1 && ctype_alpha($path[0]) && ':' === $path[1]) {
  10302. if (2 === $length) {
  10303. $root .= $path.'/';
  10304. $path = '';
  10305. } elseif ('/' === $path[2]) {
  10306. $root .= substr($path, 0, 3);
  10307. $path = $length > 3 ? substr($path, 3) : '';
  10308. }
  10309. }
  10310. return [$root, $path];
  10311. }
  10312. private static function toLower(string $string): string
  10313. {
  10314. if (false !== $encoding = mb_detect_encoding($string, null, true)) {
  10315. return mb_strtolower($string, $encoding);
  10316. }
  10317. return strtolower($string);
  10318. }
  10319. private function __construct()
  10320. {
  10321. }
  10322. }
  10323. <?php
  10324. namespace Symfony\Component\Filesystem\Exception;
  10325. interface IOExceptionInterface extends ExceptionInterface
  10326. {
  10327. public function getPath();
  10328. }
  10329. <?php
  10330. namespace Symfony\Component\Filesystem\Exception;
  10331. interface ExceptionInterface extends \Throwable
  10332. {
  10333. }
  10334. <?php
  10335. namespace Symfony\Component\Filesystem\Exception;
  10336. class RuntimeException extends \RuntimeException implements ExceptionInterface
  10337. {
  10338. }
  10339. <?php
  10340. namespace Symfony\Component\Filesystem\Exception;
  10341. class IOException extends \RuntimeException implements IOExceptionInterface
  10342. {
  10343. private $path;
  10344. public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null)
  10345. {
  10346. $this->path = $path;
  10347. parent::__construct($message, $code, $previous);
  10348. }
  10349. public function getPath()
  10350. {
  10351. return $this->path;
  10352. }
  10353. }
  10354. <?php
  10355. namespace Symfony\Component\Filesystem\Exception;
  10356. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  10357. {
  10358. }
  10359. <?php
  10360. namespace Symfony\Component\Filesystem\Exception;
  10361. class FileNotFoundException extends IOException
  10362. {
  10363. public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null)
  10364. {
  10365. if (null === $message) {
  10366. if (null === $path) {
  10367. $message = 'File could not be found.';
  10368. } else {
  10369. $message = sprintf('File "%s" could not be found.', $path);
  10370. }
  10371. }
  10372. parent::__construct($message, $code, $previous, $path);
  10373. }
  10374. }
  10375. <?php
  10376. namespace Symfony\Component\OptionsResolver;
  10377. use Symfony\Component\OptionsResolver\Exception\AccessException;
  10378. final class OptionConfigurator
  10379. {
  10380. private $name;
  10381. private $resolver;
  10382. public function __construct(string $name, OptionsResolver $resolver)
  10383. {
  10384. $this->name = $name;
  10385. $this->resolver = $resolver;
  10386. $this->resolver->setDefined($name);
  10387. }
  10388. public function allowedTypes(string ...$types): self
  10389. {
  10390. $this->resolver->setAllowedTypes($this->name, $types);
  10391. return $this;
  10392. }
  10393. public function allowedValues(...$values): self
  10394. {
  10395. $this->resolver->setAllowedValues($this->name, $values);
  10396. return $this;
  10397. }
  10398. public function default($value): self
  10399. {
  10400. $this->resolver->setDefault($this->name, $value);
  10401. return $this;
  10402. }
  10403. public function define(string $option): self
  10404. {
  10405. return $this->resolver->define($option);
  10406. }
  10407. public function deprecated(string $package, string $version, $message = 'The option "%name%" is deprecated.'): self
  10408. {
  10409. $this->resolver->setDeprecated($this->name, $package, $version, $message);
  10410. return $this;
  10411. }
  10412. public function normalize(\Closure $normalizer): self
  10413. {
  10414. $this->resolver->setNormalizer($this->name, $normalizer);
  10415. return $this;
  10416. }
  10417. public function required(): self
  10418. {
  10419. $this->resolver->setRequired($this->name);
  10420. return $this;
  10421. }
  10422. public function info(string $info): self
  10423. {
  10424. $this->resolver->setInfo($this->name, $info);
  10425. return $this;
  10426. }
  10427. }
  10428. <?php
  10429. namespace Symfony\Component\OptionsResolver;
  10430. use Symfony\Component\OptionsResolver\Exception\AccessException;
  10431. use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException;
  10432. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  10433. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  10434. use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException;
  10435. use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
  10436. use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
  10437. class OptionsResolver implements Options
  10438. {
  10439. private const VALIDATION_FUNCTIONS = [
  10440. 'bool' => 'is_bool',
  10441. 'boolean' => 'is_bool',
  10442. 'int' => 'is_int',
  10443. 'integer' => 'is_int',
  10444. 'long' => 'is_int',
  10445. 'float' => 'is_float',
  10446. 'double' => 'is_float',
  10447. 'real' => 'is_float',
  10448. 'numeric' => 'is_numeric',
  10449. 'string' => 'is_string',
  10450. 'scalar' => 'is_scalar',
  10451. 'array' => 'is_array',
  10452. 'iterable' => 'is_iterable',
  10453. 'countable' => 'is_countable',
  10454. 'callable' => 'is_callable',
  10455. 'object' => 'is_object',
  10456. 'resource' => 'is_resource',
  10457. ];
  10458. private $defined = [];
  10459. private $defaults = [];
  10460. private $nested = [];
  10461. private $required = [];
  10462. private $resolved = [];
  10463. private $normalizers = [];
  10464. private $allowedValues = [];
  10465. private $allowedTypes = [];
  10466. private $info = [];
  10467. private $lazy = [];
  10468. private $calling = [];
  10469. private $deprecated = [];
  10470. private $given = [];
  10471. private $locked = false;
  10472. private $parentsOptions = [];
  10473. private $prototype;
  10474. private $prototypeIndex;
  10475. public function setDefault(string $option, $value)
  10476. {
  10477. if ($this->locked) {
  10478. throw new AccessException('Default values cannot be set from a lazy option or normalizer.');
  10479. }
  10480. if ($value instanceof \Closure) {
  10481. $reflClosure = new \ReflectionFunction($value);
  10482. $params = $reflClosure->getParameters();
  10483. if (isset($params[0]) && Options::class === $this->getParameterClassName($params[0])) {
  10484. if (!isset($this->defaults[$option])) {
  10485. $this->defaults[$option] = null;
  10486. }
  10487. if (!isset($this->lazy[$option]) || !isset($params[1])) {
  10488. $this->lazy[$option] = [];
  10489. }
  10490. $this->lazy[$option][] = $value;
  10491. $this->defined[$option] = true;
  10492. unset($this->resolved[$option], $this->nested[$option]);
  10493. return $this;
  10494. }
  10495. if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (($type = $params[1]->getType()) instanceof \ReflectionNamedType && Options::class === $type->getName()))) {
  10496. $this->nested[$option][] = $value;
  10497. $this->defaults[$option] = [];
  10498. $this->defined[$option] = true;
  10499. unset($this->resolved[$option], $this->lazy[$option]);
  10500. return $this;
  10501. }
  10502. }
  10503. unset($this->lazy[$option], $this->nested[$option]);
  10504. if (!isset($this->defined[$option]) || \array_key_exists($option, $this->resolved)) {
  10505. $this->resolved[$option] = $value;
  10506. }
  10507. $this->defaults[$option] = $value;
  10508. $this->defined[$option] = true;
  10509. return $this;
  10510. }
  10511. public function setDefaults(array $defaults)
  10512. {
  10513. foreach ($defaults as $option => $value) {
  10514. $this->setDefault($option, $value);
  10515. }
  10516. return $this;
  10517. }
  10518. public function hasDefault(string $option)
  10519. {
  10520. return \array_key_exists($option, $this->defaults);
  10521. }
  10522. public function setRequired($optionNames)
  10523. {
  10524. if ($this->locked) {
  10525. throw new AccessException('Options cannot be made required from a lazy option or normalizer.');
  10526. }
  10527. foreach ((array) $optionNames as $option) {
  10528. $this->defined[$option] = true;
  10529. $this->required[$option] = true;
  10530. }
  10531. return $this;
  10532. }
  10533. public function isRequired(string $option)
  10534. {
  10535. return isset($this->required[$option]);
  10536. }
  10537. public function getRequiredOptions()
  10538. {
  10539. return array_keys($this->required);
  10540. }
  10541. public function isMissing(string $option)
  10542. {
  10543. return isset($this->required[$option]) && !\array_key_exists($option, $this->defaults);
  10544. }
  10545. public function getMissingOptions()
  10546. {
  10547. return array_keys(array_diff_key($this->required, $this->defaults));
  10548. }
  10549. public function setDefined($optionNames)
  10550. {
  10551. if ($this->locked) {
  10552. throw new AccessException('Options cannot be defined from a lazy option or normalizer.');
  10553. }
  10554. foreach ((array) $optionNames as $option) {
  10555. $this->defined[$option] = true;
  10556. }
  10557. return $this;
  10558. }
  10559. public function isDefined(string $option)
  10560. {
  10561. return isset($this->defined[$option]);
  10562. }
  10563. public function getDefinedOptions()
  10564. {
  10565. return array_keys($this->defined);
  10566. }
  10567. public function isNested(string $option): bool
  10568. {
  10569. return isset($this->nested[$option]);
  10570. }
  10571. public function setDeprecated(string $option): self
  10572. {
  10573. if ($this->locked) {
  10574. throw new AccessException('Options cannot be deprecated from a lazy option or normalizer.');
  10575. }
  10576. if (!isset($this->defined[$option])) {
  10577. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist, defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10578. }
  10579. $args = \func_get_args();
  10580. if (\func_num_args() < 3) {
  10581. trigger_deprecation('symfony/options-resolver', '5.1', 'The signature of method "%s()" requires 2 new arguments: "string $package, string $version", not defining them is deprecated.', __METHOD__);
  10582. $message = $args[1] ?? 'The option "%name%" is deprecated.';
  10583. $package = $version = '';
  10584. } else {
  10585. $package = $args[1];
  10586. $version = $args[2];
  10587. $message = $args[3] ?? 'The option "%name%" is deprecated.';
  10588. }
  10589. if (!\is_string($message) && !$message instanceof \Closure) {
  10590. throw new InvalidArgumentException(sprintf('Invalid type for deprecation message argument, expected string or \Closure, but got "%s".', get_debug_type($message)));
  10591. }
  10592. if ('' === $message) {
  10593. return $this;
  10594. }
  10595. $this->deprecated[$option] = [
  10596. 'package' => $package,
  10597. 'version' => $version,
  10598. 'message' => $message,
  10599. ];
  10600. unset($this->resolved[$option]);
  10601. return $this;
  10602. }
  10603. public function isDeprecated(string $option): bool
  10604. {
  10605. return isset($this->deprecated[$option]);
  10606. }
  10607. public function setNormalizer(string $option, \Closure $normalizer)
  10608. {
  10609. if ($this->locked) {
  10610. throw new AccessException('Normalizers cannot be set from a lazy option or normalizer.');
  10611. }
  10612. if (!isset($this->defined[$option])) {
  10613. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10614. }
  10615. $this->normalizers[$option] = [$normalizer];
  10616. unset($this->resolved[$option]);
  10617. return $this;
  10618. }
  10619. public function addNormalizer(string $option, \Closure $normalizer, bool $forcePrepend = false): self
  10620. {
  10621. if ($this->locked) {
  10622. throw new AccessException('Normalizers cannot be set from a lazy option or normalizer.');
  10623. }
  10624. if (!isset($this->defined[$option])) {
  10625. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10626. }
  10627. if ($forcePrepend) {
  10628. $this->normalizers[$option] = $this->normalizers[$option] ?? [];
  10629. array_unshift($this->normalizers[$option], $normalizer);
  10630. } else {
  10631. $this->normalizers[$option][] = $normalizer;
  10632. }
  10633. unset($this->resolved[$option]);
  10634. return $this;
  10635. }
  10636. public function setAllowedValues(string $option, $allowedValues)
  10637. {
  10638. if ($this->locked) {
  10639. throw new AccessException('Allowed values cannot be set from a lazy option or normalizer.');
  10640. }
  10641. if (!isset($this->defined[$option])) {
  10642. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10643. }
  10644. $this->allowedValues[$option] = \is_array($allowedValues) ? $allowedValues : [$allowedValues];
  10645. unset($this->resolved[$option]);
  10646. return $this;
  10647. }
  10648. public function addAllowedValues(string $option, $allowedValues)
  10649. {
  10650. if ($this->locked) {
  10651. throw new AccessException('Allowed values cannot be added from a lazy option or normalizer.');
  10652. }
  10653. if (!isset($this->defined[$option])) {
  10654. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10655. }
  10656. if (!\is_array($allowedValues)) {
  10657. $allowedValues = [$allowedValues];
  10658. }
  10659. if (!isset($this->allowedValues[$option])) {
  10660. $this->allowedValues[$option] = $allowedValues;
  10661. } else {
  10662. $this->allowedValues[$option] = array_merge($this->allowedValues[$option], $allowedValues);
  10663. }
  10664. unset($this->resolved[$option]);
  10665. return $this;
  10666. }
  10667. public function setAllowedTypes(string $option, $allowedTypes)
  10668. {
  10669. if ($this->locked) {
  10670. throw new AccessException('Allowed types cannot be set from a lazy option or normalizer.');
  10671. }
  10672. if (!isset($this->defined[$option])) {
  10673. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10674. }
  10675. $this->allowedTypes[$option] = (array) $allowedTypes;
  10676. unset($this->resolved[$option]);
  10677. return $this;
  10678. }
  10679. public function addAllowedTypes(string $option, $allowedTypes)
  10680. {
  10681. if ($this->locked) {
  10682. throw new AccessException('Allowed types cannot be added from a lazy option or normalizer.');
  10683. }
  10684. if (!isset($this->defined[$option])) {
  10685. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10686. }
  10687. if (!isset($this->allowedTypes[$option])) {
  10688. $this->allowedTypes[$option] = (array) $allowedTypes;
  10689. } else {
  10690. $this->allowedTypes[$option] = array_merge($this->allowedTypes[$option], (array) $allowedTypes);
  10691. }
  10692. unset($this->resolved[$option]);
  10693. return $this;
  10694. }
  10695. public function define(string $option): OptionConfigurator
  10696. {
  10697. if (isset($this->defined[$option])) {
  10698. throw new OptionDefinitionException(sprintf('The option "%s" is already defined.', $option));
  10699. }
  10700. return new OptionConfigurator($option, $this);
  10701. }
  10702. public function setInfo(string $option, string $info): self
  10703. {
  10704. if ($this->locked) {
  10705. throw new AccessException('The Info message cannot be set from a lazy option or normalizer.');
  10706. }
  10707. if (!isset($this->defined[$option])) {
  10708. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10709. }
  10710. $this->info[$option] = $info;
  10711. return $this;
  10712. }
  10713. public function getInfo(string $option): ?string
  10714. {
  10715. if (!isset($this->defined[$option])) {
  10716. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10717. }
  10718. return $this->info[$option] ?? null;
  10719. }
  10720. public function setPrototype(bool $prototype): self
  10721. {
  10722. if ($this->locked) {
  10723. throw new AccessException('The prototype property cannot be set from a lazy option or normalizer.');
  10724. }
  10725. if (null === $this->prototype && $prototype) {
  10726. throw new AccessException('The prototype property cannot be set from a root definition.');
  10727. }
  10728. $this->prototype = $prototype;
  10729. return $this;
  10730. }
  10731. public function isPrototype(): bool
  10732. {
  10733. return $this->prototype ?? false;
  10734. }
  10735. public function remove($optionNames)
  10736. {
  10737. if ($this->locked) {
  10738. throw new AccessException('Options cannot be removed from a lazy option or normalizer.');
  10739. }
  10740. foreach ((array) $optionNames as $option) {
  10741. unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]);
  10742. unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option], $this->info[$option]);
  10743. }
  10744. return $this;
  10745. }
  10746. public function clear()
  10747. {
  10748. if ($this->locked) {
  10749. throw new AccessException('Options cannot be cleared from a lazy option or normalizer.');
  10750. }
  10751. $this->defined = [];
  10752. $this->defaults = [];
  10753. $this->nested = [];
  10754. $this->required = [];
  10755. $this->resolved = [];
  10756. $this->lazy = [];
  10757. $this->normalizers = [];
  10758. $this->allowedTypes = [];
  10759. $this->allowedValues = [];
  10760. $this->deprecated = [];
  10761. $this->info = [];
  10762. return $this;
  10763. }
  10764. public function resolve(array $options = [])
  10765. {
  10766. if ($this->locked) {
  10767. throw new AccessException('Options cannot be resolved from a lazy option or normalizer.');
  10768. }
  10769. $clone = clone $this;
  10770. $diff = array_diff_key($options, $clone->defined);
  10771. if (\count($diff) > 0) {
  10772. ksort($clone->defined);
  10773. ksort($diff);
  10774. throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', $this->formatOptions(array_keys($diff)), implode('", "', array_keys($clone->defined))));
  10775. }
  10776. foreach ($options as $option => $value) {
  10777. $clone->given[$option] = true;
  10778. $clone->defaults[$option] = $value;
  10779. unset($clone->resolved[$option], $clone->lazy[$option]);
  10780. }
  10781. $diff = array_diff_key($clone->required, $clone->defaults);
  10782. if (\count($diff) > 0) {
  10783. ksort($diff);
  10784. throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', $this->formatOptions(array_keys($diff))));
  10785. }
  10786. $clone->locked = true;
  10787. foreach ($clone->defaults as $option => $_) {
  10788. $clone->offsetGet($option);
  10789. }
  10790. return $clone->resolved;
  10791. }
  10792. #[\ReturnTypeWillChange]
  10793. public function offsetGet($option, bool $triggerDeprecation = true)
  10794. {
  10795. if (!$this->locked) {
  10796. throw new AccessException('Array access is only supported within closures of lazy options and normalizers.');
  10797. }
  10798. if (isset($this->resolved[$option]) || \array_key_exists($option, $this->resolved)) {
  10799. if ($triggerDeprecation && isset($this->deprecated[$option]) && (isset($this->given[$option]) || $this->calling) && \is_string($this->deprecated[$option]['message'])) {
  10800. trigger_deprecation($this->deprecated[$option]['package'], $this->deprecated[$option]['version'], strtr($this->deprecated[$option]['message'], ['%name%' => $option]));
  10801. }
  10802. return $this->resolved[$option];
  10803. }
  10804. if (!isset($this->defaults[$option]) && !\array_key_exists($option, $this->defaults)) {
  10805. if (!isset($this->defined[$option])) {
  10806. throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
  10807. }
  10808. throw new NoSuchOptionException(sprintf('The optional option "%s" has no value set. You should make sure it is set with "isset" before reading it.', $this->formatOptions([$option])));
  10809. }
  10810. $value = $this->defaults[$option];
  10811. if (isset($this->nested[$option])) {
  10812. if (isset($this->calling[$option])) {
  10813. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling))));
  10814. }
  10815. if (!\is_array($value)) {
  10816. throw new InvalidOptionsException(sprintf('The nested option "%s" with value %s is expected to be of type array, but is of type "%s".', $this->formatOptions([$option]), $this->formatValue($value), get_debug_type($value)));
  10817. }
  10818. $this->calling[$option] = true;
  10819. try {
  10820. $resolver = new self();
  10821. $resolver->prototype = false;
  10822. $resolver->parentsOptions = $this->parentsOptions;
  10823. $resolver->parentsOptions[] = $option;
  10824. foreach ($this->nested[$option] as $closure) {
  10825. $closure($resolver, $this);
  10826. }
  10827. if ($resolver->prototype) {
  10828. $values = [];
  10829. foreach ($value as $index => $prototypeValue) {
  10830. if (!\is_array($prototypeValue)) {
  10831. throw new InvalidOptionsException(sprintf('The value of the option "%s" is expected to be of type array of array, but is of type array of "%s".', $this->formatOptions([$option]), get_debug_type($prototypeValue)));
  10832. }
  10833. $resolver->prototypeIndex = $index;
  10834. $values[$index] = $resolver->resolve($prototypeValue);
  10835. }
  10836. $value = $values;
  10837. } else {
  10838. $value = $resolver->resolve($value);
  10839. }
  10840. } finally {
  10841. $resolver->prototypeIndex = null;
  10842. unset($this->calling[$option]);
  10843. }
  10844. }
  10845. if (isset($this->lazy[$option])) {
  10846. if (isset($this->calling[$option])) {
  10847. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling))));
  10848. }
  10849. $this->calling[$option] = true;
  10850. try {
  10851. foreach ($this->lazy[$option] as $closure) {
  10852. $value = $closure($this, $value);
  10853. }
  10854. } finally {
  10855. unset($this->calling[$option]);
  10856. }
  10857. }
  10858. if (isset($this->allowedTypes[$option])) {
  10859. $valid = true;
  10860. $invalidTypes = [];
  10861. foreach ($this->allowedTypes[$option] as $type) {
  10862. if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) {
  10863. break;
  10864. }
  10865. }
  10866. if (!$valid) {
  10867. $fmtActualValue = $this->formatValue($value);
  10868. $fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
  10869. $fmtProvidedTypes = implode('|', array_keys($invalidTypes));
  10870. $allowedContainsArrayType = \count(array_filter($this->allowedTypes[$option], static function ($item) {
  10871. return str_ends_with($item, '[]');
  10872. })) > 0;
  10873. if (\is_array($value) && $allowedContainsArrayType) {
  10874. throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $this->formatOptions([$option]), $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
  10875. }
  10876. throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $this->formatOptions([$option]), $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
  10877. }
  10878. }
  10879. if (isset($this->allowedValues[$option])) {
  10880. $success = false;
  10881. $printableAllowedValues = [];
  10882. foreach ($this->allowedValues[$option] as $allowedValue) {
  10883. if ($allowedValue instanceof \Closure) {
  10884. if ($allowedValue($value)) {
  10885. $success = true;
  10886. break;
  10887. }
  10888. continue;
  10889. }
  10890. if ($value === $allowedValue) {
  10891. $success = true;
  10892. break;
  10893. }
  10894. $printableAllowedValues[] = $allowedValue;
  10895. }
  10896. if (!$success) {
  10897. $message = sprintf(
  10898. 'The option "%s" with value %s is invalid.',
  10899. $option,
  10900. $this->formatValue($value)
  10901. );
  10902. if (\count($printableAllowedValues) > 0) {
  10903. $message .= sprintf(
  10904. ' Accepted values are: %s.',
  10905. $this->formatValues($printableAllowedValues)
  10906. );
  10907. }
  10908. if (isset($this->info[$option])) {
  10909. $message .= sprintf(' Info: %s.', $this->info[$option]);
  10910. }
  10911. throw new InvalidOptionsException($message);
  10912. }
  10913. }
  10914. if ($triggerDeprecation && isset($this->deprecated[$option]) && (isset($this->given[$option]) || ($this->calling && \is_string($this->deprecated[$option]['message'])))) {
  10915. $deprecation = $this->deprecated[$option];
  10916. $message = $this->deprecated[$option]['message'];
  10917. if ($message instanceof \Closure) {
  10918. if (isset($this->calling[$option])) {
  10919. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling))));
  10920. }
  10921. $this->calling[$option] = true;
  10922. try {
  10923. if (!\is_string($message = $message($this, $value))) {
  10924. throw new InvalidOptionsException(sprintf('Invalid type for deprecation message, expected string but got "%s", return an empty string to ignore.', get_debug_type($message)));
  10925. }
  10926. } finally {
  10927. unset($this->calling[$option]);
  10928. }
  10929. }
  10930. if ('' !== $message) {
  10931. trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option]));
  10932. }
  10933. }
  10934. if (isset($this->normalizers[$option])) {
  10935. if (isset($this->calling[$option])) {
  10936. throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling))));
  10937. }
  10938. $this->calling[$option] = true;
  10939. try {
  10940. foreach ($this->normalizers[$option] as $normalizer) {
  10941. $value = $normalizer($this, $value);
  10942. }
  10943. } finally {
  10944. unset($this->calling[$option]);
  10945. }
  10946. }
  10947. $this->resolved[$option] = $value;
  10948. return $value;
  10949. }
  10950. private function verifyTypes(string $type, $value, array &$invalidTypes, int $level = 0): bool
  10951. {
  10952. if (\is_array($value) && '[]' === substr($type, -2)) {
  10953. $type = substr($type, 0, -2);
  10954. $valid = true;
  10955. foreach ($value as $val) {
  10956. if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) {
  10957. $valid = false;
  10958. }
  10959. }
  10960. return $valid;
  10961. }
  10962. if (('null' === $type && null === $value) || (isset(self::VALIDATION_FUNCTIONS[$type]) ? self::VALIDATION_FUNCTIONS[$type]($value) : $value instanceof $type)) {
  10963. return true;
  10964. }
  10965. if (!$invalidTypes || $level > 0) {
  10966. $invalidTypes[get_debug_type($value)] = true;
  10967. }
  10968. return false;
  10969. }
  10970. #[\ReturnTypeWillChange]
  10971. public function offsetExists($option)
  10972. {
  10973. if (!$this->locked) {
  10974. throw new AccessException('Array access is only supported within closures of lazy options and normalizers.');
  10975. }
  10976. return \array_key_exists($option, $this->defaults);
  10977. }
  10978. #[\ReturnTypeWillChange]
  10979. public function offsetSet($option, $value)
  10980. {
  10981. throw new AccessException('Setting options via array access is not supported. Use setDefault() instead.');
  10982. }
  10983. #[\ReturnTypeWillChange]
  10984. public function offsetUnset($option)
  10985. {
  10986. throw new AccessException('Removing options via array access is not supported. Use remove() instead.');
  10987. }
  10988. #[\ReturnTypeWillChange]
  10989. public function count()
  10990. {
  10991. if (!$this->locked) {
  10992. throw new AccessException('Counting is only supported within closures of lazy options and normalizers.');
  10993. }
  10994. return \count($this->defaults);
  10995. }
  10996. private function formatValue($value): string
  10997. {
  10998. if (\is_object($value)) {
  10999. return \get_class($value);
  11000. }
  11001. if (\is_array($value)) {
  11002. return 'array';
  11003. }
  11004. if (\is_string($value)) {
  11005. return '"'.$value.'"';
  11006. }
  11007. if (\is_resource($value)) {
  11008. return 'resource';
  11009. }
  11010. if (null === $value) {
  11011. return 'null';
  11012. }
  11013. if (false === $value) {
  11014. return 'false';
  11015. }
  11016. if (true === $value) {
  11017. return 'true';
  11018. }
  11019. return (string) $value;
  11020. }
  11021. private function formatValues(array $values): string
  11022. {
  11023. foreach ($values as $key => $value) {
  11024. $values[$key] = $this->formatValue($value);
  11025. }
  11026. return implode(', ', $values);
  11027. }
  11028. private function formatOptions(array $options): string
  11029. {
  11030. if ($this->parentsOptions) {
  11031. $prefix = array_shift($this->parentsOptions);
  11032. if ($this->parentsOptions) {
  11033. $prefix .= sprintf('[%s]', implode('][', $this->parentsOptions));
  11034. }
  11035. if ($this->prototype && null !== $this->prototypeIndex) {
  11036. $prefix .= sprintf('[%s]', $this->prototypeIndex);
  11037. }
  11038. $options = array_map(static function (string $option) use ($prefix): string {
  11039. return sprintf('%s[%s]', $prefix, $option);
  11040. }, $options);
  11041. }
  11042. return implode('", "', $options);
  11043. }
  11044. private function getParameterClassName(\ReflectionParameter $parameter): ?string
  11045. {
  11046. if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) {
  11047. return null;
  11048. }
  11049. return $type->getName();
  11050. }
  11051. }
  11052. <?php
  11053. namespace Symfony\Component\OptionsResolver;
  11054. interface Options extends \ArrayAccess, \Countable
  11055. {
  11056. }
  11057. <?php
  11058. namespace Symfony\Component\OptionsResolver\Exception;
  11059. class InvalidOptionsException extends InvalidArgumentException
  11060. {
  11061. }
  11062. <?php
  11063. namespace Symfony\Component\OptionsResolver\Exception;
  11064. class MissingOptionsException extends InvalidArgumentException
  11065. {
  11066. }
  11067. <?php
  11068. namespace Symfony\Component\OptionsResolver\Exception;
  11069. class AccessException extends \LogicException implements ExceptionInterface
  11070. {
  11071. }
  11072. <?php
  11073. namespace Symfony\Component\OptionsResolver\Exception;
  11074. class OptionDefinitionException extends \LogicException implements ExceptionInterface
  11075. {
  11076. }
  11077. <?php
  11078. namespace Symfony\Component\OptionsResolver\Exception;
  11079. interface ExceptionInterface extends \Throwable
  11080. {
  11081. }
  11082. <?php
  11083. namespace Symfony\Component\OptionsResolver\Exception;
  11084. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  11085. {
  11086. }
  11087. <?php
  11088. namespace Symfony\Component\OptionsResolver\Exception;
  11089. class NoSuchOptionException extends \OutOfBoundsException implements ExceptionInterface
  11090. {
  11091. }
  11092. <?php
  11093. namespace Symfony\Component\OptionsResolver\Exception;
  11094. use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
  11095. class NoConfigurationException extends \RuntimeException implements ExceptionInterface
  11096. {
  11097. }
  11098. <?php
  11099. namespace Symfony\Component\OptionsResolver\Exception;
  11100. class UndefinedOptionsException extends InvalidArgumentException
  11101. {
  11102. }
  11103. <?php
  11104. namespace Symfony\Component\OptionsResolver\Debug;
  11105. use Symfony\Component\OptionsResolver\Exception\NoConfigurationException;
  11106. use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
  11107. use Symfony\Component\OptionsResolver\OptionsResolver;
  11108. class OptionsResolverIntrospector
  11109. {
  11110. private $get;
  11111. public function __construct(OptionsResolver $optionsResolver)
  11112. {
  11113. $this->get = \Closure::bind(function ($property, $option, $message) {
  11114. if (!$this->isDefined($option)) {
  11115. throw new UndefinedOptionsException(sprintf('The option "%s" does not exist.', $option));
  11116. }
  11117. if (!\array_key_exists($option, $this->{$property})) {
  11118. throw new NoConfigurationException($message);
  11119. }
  11120. return $this->{$property}[$option];
  11121. }, $optionsResolver, $optionsResolver);
  11122. }
  11123. public function getDefault(string $option)
  11124. {
  11125. return ($this->get)('defaults', $option, sprintf('No default value was set for the "%s" option.', $option));
  11126. }
  11127. public function getLazyClosures(string $option): array
  11128. {
  11129. return ($this->get)('lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option));
  11130. }
  11131. public function getAllowedTypes(string $option): array
  11132. {
  11133. return ($this->get)('allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option));
  11134. }
  11135. public function getAllowedValues(string $option): array
  11136. {
  11137. return ($this->get)('allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option));
  11138. }
  11139. public function getNormalizer(string $option): \Closure
  11140. {
  11141. return current($this->getNormalizers($option));
  11142. }
  11143. public function getNormalizers(string $option): array
  11144. {
  11145. return ($this->get)('normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option));
  11146. }
  11147. public function getDeprecationMessage(string $option)
  11148. {
  11149. trigger_deprecation('symfony/options-resolver', '5.1', 'The "%s()" method is deprecated, use "getDeprecation()" instead.', __METHOD__);
  11150. return $this->getDeprecation($option)['message'];
  11151. }
  11152. public function getDeprecation(string $option): array
  11153. {
  11154. return ($this->get)('deprecated', $option, sprintf('No deprecation was set for the "%s" option.', $option));
  11155. }
  11156. }
  11157. <?php
  11158. use Symfony\Polyfill\Intl\Normalizer as p;
  11159. if (!function_exists('normalizer_is_normalized')) {
  11160. function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); }
  11161. }
  11162. if (!function_exists('normalizer_normalize')) {
  11163. function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); }
  11164. }
  11165. <?php
  11166. namespace Symfony\Polyfill\Intl\Normalizer;
  11167. class Normalizer
  11168. {
  11169. public const FORM_D = \Normalizer::FORM_D;
  11170. public const FORM_KD = \Normalizer::FORM_KD;
  11171. public const FORM_C = \Normalizer::FORM_C;
  11172. public const FORM_KC = \Normalizer::FORM_KC;
  11173. public const NFD = \Normalizer::NFD;
  11174. public const NFKD = \Normalizer::NFKD;
  11175. public const NFC = \Normalizer::NFC;
  11176. public const NFKC = \Normalizer::NFKC;
  11177. private static $C;
  11178. private static $D;
  11179. private static $KD;
  11180. private static $cC;
  11181. private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
  11182. private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
  11183. public static function isNormalized(string $s, int $form = self::FORM_C)
  11184. {
  11185. if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {
  11186. return false;
  11187. }
  11188. if (!isset($s[strspn($s, self::$ASCII)])) {
  11189. return true;
  11190. }
  11191. if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) {
  11192. return true;
  11193. }
  11194. return self::normalize($s, $form) === $s;
  11195. }
  11196. public static function normalize(string $s, int $form = self::FORM_C)
  11197. {
  11198. if (!preg_match('//u', $s)) {
  11199. return false;
  11200. }
  11201. switch ($form) {
  11202. case self::NFC: $C = true; $K = false; break;
  11203. case self::NFD: $C = false; $K = false; break;
  11204. case self::NFKC: $C = true; $K = true; break;
  11205. case self::NFKD: $C = false; $K = true; break;
  11206. default:
  11207. if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) {
  11208. return $s;
  11209. }
  11210. if (80000 > \PHP_VERSION_ID) {
  11211. return false;
  11212. }
  11213. throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');
  11214. }
  11215. if ('' === $s) {
  11216. return '';
  11217. }
  11218. if ($K && null === self::$KD) {
  11219. self::$KD = self::getData('compatibilityDecomposition');
  11220. }
  11221. if (null === self::$D) {
  11222. self::$D = self::getData('canonicalDecomposition');
  11223. self::$cC = self::getData('combiningClass');
  11224. }
  11225. if (null !== $mbEncoding = (2 & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {
  11226. mb_internal_encoding('8bit');
  11227. }
  11228. $r = self::decompose($s, $K);
  11229. if ($C) {
  11230. if (null === self::$C) {
  11231. self::$C = self::getData('canonicalComposition');
  11232. }
  11233. $r = self::recompose($r);
  11234. }
  11235. if (null !== $mbEncoding) {
  11236. mb_internal_encoding($mbEncoding);
  11237. }
  11238. return $r;
  11239. }
  11240. private static function recompose($s)
  11241. {
  11242. $ASCII = self::$ASCII;
  11243. $compMap = self::$C;
  11244. $combClass = self::$cC;
  11245. $ulenMask = self::$ulenMask;
  11246. $result = $tail = '';
  11247. $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"];
  11248. $len = \strlen($s);
  11249. $lastUchr = substr($s, 0, $i);
  11250. $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;
  11251. while ($i < $len) {
  11252. if ($s[$i] < "\x80") {
  11253. if ($tail) {
  11254. $lastUchr .= $tail;
  11255. $tail = '';
  11256. }
  11257. if ($j = strspn($s, $ASCII, $i + 1)) {
  11258. $lastUchr .= substr($s, $i, $j);
  11259. $i += $j;
  11260. }
  11261. $result .= $lastUchr;
  11262. $lastUchr = $s[$i];
  11263. $lastUcls = 0;
  11264. ++$i;
  11265. continue;
  11266. }
  11267. $ulen = $ulenMask[$s[$i] & "\xF0"];
  11268. $uchr = substr($s, $i, $ulen);
  11269. if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr
  11270. || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
  11271. || $lastUcls) {
  11272. $ucls = $combClass[$uchr] ?? 0;
  11273. if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {
  11274. $lastUchr = $compMap[$lastUchr.$uchr];
  11275. } elseif ($lastUcls = $ucls) {
  11276. $tail .= $uchr;
  11277. } else {
  11278. if ($tail) {
  11279. $lastUchr .= $tail;
  11280. $tail = '';
  11281. }
  11282. $result .= $lastUchr;
  11283. $lastUchr = $uchr;
  11284. }
  11285. } else {
  11286. $L = \ord($lastUchr[2]) - 0x80;
  11287. $V = \ord($uchr[2]) - 0xA1;
  11288. $T = 0;
  11289. $uchr = substr($s, $i + $ulen, 3);
  11290. if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") {
  11291. $T = \ord($uchr[2]) - 0xA7;
  11292. 0 > $T && $T += 0x40;
  11293. $ulen += 3;
  11294. }
  11295. $L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
  11296. $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F);
  11297. }
  11298. $i += $ulen;
  11299. }
  11300. return $result.$lastUchr.$tail;
  11301. }
  11302. private static function decompose($s, $c)
  11303. {
  11304. $result = '';
  11305. $ASCII = self::$ASCII;
  11306. $decompMap = self::$D;
  11307. $combClass = self::$cC;
  11308. $ulenMask = self::$ulenMask;
  11309. if ($c) {
  11310. $compatMap = self::$KD;
  11311. }
  11312. $c = [];
  11313. $i = 0;
  11314. $len = \strlen($s);
  11315. while ($i < $len) {
  11316. if ($s[$i] < "\x80") {
  11317. if ($c) {
  11318. ksort($c);
  11319. $result .= implode('', $c);
  11320. $c = [];
  11321. }
  11322. $j = 1 + strspn($s, $ASCII, $i + 1);
  11323. $result .= substr($s, $i, $j);
  11324. $i += $j;
  11325. continue;
  11326. }
  11327. $ulen = $ulenMask[$s[$i] & "\xF0"];
  11328. $uchr = substr($s, $i, $ulen);
  11329. $i += $ulen;
  11330. if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {
  11331. if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {
  11332. $uchr = $j;
  11333. $j = \strlen($uchr);
  11334. $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"];
  11335. if ($ulen != $j) {
  11336. $j -= $ulen;
  11337. $i -= $j;
  11338. if (0 > $i) {
  11339. $s = str_repeat(' ', -$i).$s;
  11340. $len -= $i;
  11341. $i = 0;
  11342. }
  11343. while ($j--) {
  11344. $s[$i + $j] = $uchr[$ulen + $j];
  11345. }
  11346. $uchr = substr($uchr, 0, $ulen);
  11347. }
  11348. }
  11349. if (isset($combClass[$uchr])) {
  11350. if (!isset($c[$combClass[$uchr]])) {
  11351. $c[$combClass[$uchr]] = '';
  11352. }
  11353. $c[$combClass[$uchr]] .= $uchr;
  11354. continue;
  11355. }
  11356. } else {
  11357. $uchr = unpack('C*', $uchr);
  11358. $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;
  11359. $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588))
  11360. ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28));
  11361. if ($j %= 28) {
  11362. $uchr .= $j < 25
  11363. ? ("\xE1\x86".\chr(0xA7 + $j))
  11364. : ("\xE1\x87".\chr(0x67 + $j));
  11365. }
  11366. }
  11367. if ($c) {
  11368. ksort($c);
  11369. $result .= implode('', $c);
  11370. $c = [];
  11371. }
  11372. $result .= $uchr;
  11373. }
  11374. if ($c) {
  11375. ksort($c);
  11376. $result .= implode('', $c);
  11377. }
  11378. return $result;
  11379. }
  11380. private static function getData($file)
  11381. {
  11382. if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
  11383. return require $file;
  11384. }
  11385. return false;
  11386. }
  11387. }
  11388. <?php
  11389. class Normalizer extends Symfony\Polyfill\Intl\Normalizer\Normalizer
  11390. {
  11391. public const NONE = 2;
  11392. public const FORM_D = 4;
  11393. public const FORM_KD = 8;
  11394. public const FORM_C = 16;
  11395. public const FORM_KC = 32;
  11396. public const NFD = 4;
  11397. public const NFKD = 8;
  11398. public const NFC = 16;
  11399. public const NFKC = 32;
  11400. }
  11401. <?php
  11402. return array (
  11403. 'Ì€' => 230,
  11404. '�' => 230,
  11405. 'Ì‚' => 230,
  11406. '̃' => 230,
  11407. 'Ì„' => 230,
  11408. 'Ì…' => 230,
  11409. '̆' => 230,
  11410. '̇' => 230,
  11411. '̈' => 230,
  11412. '̉' => 230,
  11413. 'ÌŠ' => 230,
  11414. 'Ì‹' => 230,
  11415. '̌' => 230,
  11416. '�' => 230,
  11417. 'ÌŽ' => 230,
  11418. '�' => 230,
  11419. '�' => 230,
  11420. 'Ì‘' => 230,
  11421. 'Ì’' => 230,
  11422. 'Ì“' => 230,
  11423. 'Ì”' => 230,
  11424. 'Ì•' => 232,
  11425. 'Ì–' => 220,
  11426. 'Ì—' => 220,
  11427. '̘' => 220,
  11428. 'Ì™' => 220,
  11429. 'Ìš' => 232,
  11430. 'Ì›' => 216,
  11431. '̜' => 220,
  11432. '�' => 220,
  11433. 'Ìž' => 220,
  11434. 'ÌŸ' => 220,
  11435. 'Ì ' => 220,
  11436. 'Ì¡' => 202,
  11437. 'Ì¢' => 202,
  11438. 'Ì£' => 220,
  11439. '̤' => 220,
  11440. 'Ì¥' => 220,
  11441. '̦' => 220,
  11442. '̧' => 202,
  11443. '̨' => 202,
  11444. 'Ì©' => 220,
  11445. '̪' => 220,
  11446. 'Ì«' => 220,
  11447. '̬' => 220,
  11448. 'Ì­' => 220,
  11449. 'Ì®' => 220,
  11450. '̯' => 220,
  11451. '̰' => 220,
  11452. '̱' => 220,
  11453. '̲' => 220,
  11454. '̳' => 220,
  11455. 'Ì´' => 1,
  11456. '̵' => 1,
  11457. '̶' => 1,
  11458. 'Ì·' => 1,
  11459. '̸' => 1,
  11460. '̹' => 220,
  11461. '̺' => 220,
  11462. 'Ì»' => 220,
  11463. '̼' => 220,
  11464. '̽' => 230,
  11465. '̾' => 230,
  11466. 'Ì¿' => 230,
  11467. 'Í€' => 230,
  11468. '�' => 230,
  11469. 'Í‚' => 230,
  11470. '̓' => 230,
  11471. 'Í„' => 230,
  11472. 'Í…' => 240,
  11473. '͆' => 230,
  11474. '͇' => 220,
  11475. '͈' => 220,
  11476. '͉' => 220,
  11477. 'ÍŠ' => 230,
  11478. 'Í‹' => 230,
  11479. '͌' => 230,
  11480. '�' => 220,
  11481. 'ÍŽ' => 220,
  11482. '�' => 230,
  11483. 'Í‘' => 230,
  11484. 'Í’' => 230,
  11485. 'Í“' => 220,
  11486. 'Í”' => 220,
  11487. 'Í•' => 220,
  11488. 'Í–' => 220,
  11489. 'Í—' => 230,
  11490. '͘' => 232,
  11491. 'Í™' => 220,
  11492. 'Íš' => 220,
  11493. 'Í›' => 230,
  11494. '͜' => 233,
  11495. '�' => 234,
  11496. 'Íž' => 234,
  11497. 'ÍŸ' => 233,
  11498. 'Í ' => 234,
  11499. 'Í¡' => 234,
  11500. 'Í¢' => 233,
  11501. 'Í£' => 230,
  11502. 'ͤ' => 230,
  11503. 'Í¥' => 230,
  11504. 'ͦ' => 230,
  11505. 'ͧ' => 230,
  11506. 'ͨ' => 230,
  11507. 'Í©' => 230,
  11508. 'ͪ' => 230,
  11509. 'Í«' => 230,
  11510. 'ͬ' => 230,
  11511. 'Í­' => 230,
  11512. 'Í®' => 230,
  11513. 'ͯ' => 230,
  11514. 'Òƒ' => 230,
  11515. 'Ò„' => 230,
  11516. 'Ò…' => 230,
  11517. 'Ò†' => 230,
  11518. 'Ò‡' => 230,
  11519. 'Ö‘' => 220,
  11520. 'Ö’' => 230,
  11521. 'Ö“' => 230,
  11522. 'Ö”' => 230,
  11523. 'Ö•' => 230,
  11524. 'Ö–' => 220,
  11525. 'Ö—' => 230,
  11526. 'Ö˜' => 230,
  11527. 'Ö™' => 230,
  11528. 'Öš' => 222,
  11529. 'Ö›' => 220,
  11530. '֜' => 230,
  11531. 'Ö�' => 230,
  11532. 'Öž' => 230,
  11533. 'ÖŸ' => 230,
  11534. 'Ö ' => 230,
  11535. 'Ö¡' => 230,
  11536. 'Ö¢' => 220,
  11537. 'Ö£' => 220,
  11538. 'Ö¤' => 220,
  11539. 'Ö¥' => 220,
  11540. 'Ö¦' => 220,
  11541. 'Ö§' => 220,
  11542. 'Ö¨' => 230,
  11543. 'Ö©' => 230,
  11544. 'Öª' => 220,
  11545. 'Ö«' => 230,
  11546. 'Ö¬' => 230,
  11547. 'Ö­' => 222,
  11548. 'Ö®' => 228,
  11549. 'Ö¯' => 230,
  11550. 'Ö°' => 10,
  11551. 'Ö±' => 11,
  11552. 'Ö²' => 12,
  11553. 'Ö³' => 13,
  11554. 'Ö´' => 14,
  11555. 'Öµ' => 15,
  11556. 'Ö¶' => 16,
  11557. 'Ö·' => 17,
  11558. 'Ö¸' => 18,
  11559. 'Ö¹' => 19,
  11560. 'Öº' => 19,
  11561. 'Ö»' => 20,
  11562. 'Ö¼' => 21,
  11563. 'Ö½' => 22,
  11564. 'Ö¿' => 23,
  11565. '�' => 24,
  11566. 'ׂ' => 25,
  11567. 'ׄ' => 230,
  11568. '×…' => 220,
  11569. 'ׇ' => 18,
  11570. '�' => 230,
  11571. 'Ø‘' => 230,
  11572. 'Ø’' => 230,
  11573. 'Ø“' => 230,
  11574. 'Ø”' => 230,
  11575. 'Ø•' => 230,
  11576. 'Ø–' => 230,
  11577. 'Ø—' => 230,
  11578. 'ؘ' => 30,
  11579. 'Ø™' => 31,
  11580. 'Øš' => 32,
  11581. 'Ù‹' => 27,
  11582. 'ٌ' => 28,
  11583. 'Ù�' => 29,
  11584. 'ÙŽ' => 30,
  11585. 'Ù�' => 31,
  11586. 'Ù�' => 32,
  11587. 'Ù‘' => 33,
  11588. 'Ù’' => 34,
  11589. 'Ù“' => 230,
  11590. 'Ù”' => 230,
  11591. 'Ù•' => 220,
  11592. 'Ù–' => 220,
  11593. 'Ù—' => 230,
  11594. 'Ù˜' => 230,
  11595. 'Ù™' => 230,
  11596. 'Ùš' => 230,
  11597. 'Ù›' => 230,
  11598. 'ٜ' => 220,
  11599. 'Ù�' => 230,
  11600. 'Ùž' => 230,
  11601. 'ÙŸ' => 220,
  11602. 'Ù°' => 35,
  11603. 'Û–' => 230,
  11604. 'Û—' => 230,
  11605. 'Û˜' => 230,
  11606. 'Û™' => 230,
  11607. 'Ûš' => 230,
  11608. 'Û›' => 230,
  11609. 'ۜ' => 230,
  11610. 'ÛŸ' => 230,
  11611. 'Û ' => 230,
  11612. 'Û¡' => 230,
  11613. 'Û¢' => 230,
  11614. 'Û£' => 220,
  11615. 'Û¤' => 230,
  11616. 'Û§' => 230,
  11617. 'Û¨' => 230,
  11618. 'Ûª' => 220,
  11619. 'Û«' => 230,
  11620. 'Û¬' => 230,
  11621. 'Û­' => 220,
  11622. 'Ü‘' => 36,
  11623. 'ܰ' => 230,
  11624. 'ܱ' => 220,
  11625. 'ܲ' => 230,
  11626. 'ܳ' => 230,
  11627. 'Ü´' => 220,
  11628. 'ܵ' => 230,
  11629. 'ܶ' => 230,
  11630. 'Ü·' => 220,
  11631. 'ܸ' => 220,
  11632. 'ܹ' => 220,
  11633. 'ܺ' => 230,
  11634. 'Ü»' => 220,
  11635. 'ܼ' => 220,
  11636. 'ܽ' => 230,
  11637. 'ܾ' => 220,
  11638. 'Ü¿' => 230,
  11639. 'Ý€' => 230,
  11640. '�' => 230,
  11641. 'Ý‚' => 220,
  11642. '݃' => 230,
  11643. 'Ý„' => 220,
  11644. 'Ý…' => 230,
  11645. '݆' => 220,
  11646. '݇' => 230,
  11647. '݈' => 220,
  11648. '݉' => 230,
  11649. 'ÝŠ' => 230,
  11650. 'ß«' => 230,
  11651. '߬' => 230,
  11652. 'ß­' => 230,
  11653. 'ß®' => 230,
  11654. '߯' => 230,
  11655. 'ß°' => 230,
  11656. 'ß±' => 230,
  11657. 'ß²' => 220,
  11658. 'ß³' => 230,
  11659. 'ß½' => 220,
  11660. 'à –' => 230,
  11661. 'à —' => 230,
  11662. 'à ˜' => 230,
  11663. 'à ™' => 230,
  11664. 'à ›' => 230,
  11665. 'ࠜ' => 230,
  11666. 'à �' => 230,
  11667. 'à ž' => 230,
  11668. 'à Ÿ' => 230,
  11669. 'à  ' => 230,
  11670. 'à ¡' => 230,
  11671. 'à ¢' => 230,
  11672. 'à £' => 230,
  11673. 'à ¥' => 230,
  11674. 'à ¦' => 230,
  11675. 'à §' => 230,
  11676. 'à ©' => 230,
  11677. 'à ª' => 230,
  11678. 'à «' => 230,
  11679. 'à ¬' => 230,
  11680. 'à ­' => 230,
  11681. 'à¡™' => 220,
  11682. '࡚' => 220,
  11683. 'à¡›' => 220,
  11684. '࣓' => 220,
  11685. 'ࣔ' => 230,
  11686. 'ࣕ' => 230,
  11687. 'ࣖ' => 230,
  11688. 'ࣗ' => 230,
  11689. 'ࣘ' => 230,
  11690. 'ࣙ' => 230,
  11691. 'ࣚ' => 230,
  11692. 'ࣛ' => 230,
  11693. 'ࣜ' => 230,
  11694. '�' => 230,
  11695. 'ࣞ' => 230,
  11696. 'ࣟ' => 230,
  11697. '࣠' => 230,
  11698. '࣡' => 230,
  11699. 'ࣣ' => 220,
  11700. 'ࣤ' => 230,
  11701. 'ࣥ' => 230,
  11702. 'ࣦ' => 220,
  11703. 'ࣧ' => 230,
  11704. 'ࣨ' => 230,
  11705. 'ࣩ' => 220,
  11706. '࣪' => 230,
  11707. '࣫' => 230,
  11708. '࣬' => 230,
  11709. '࣭' => 220,
  11710. '࣮' => 220,
  11711. '࣯' => 220,
  11712. 'ࣰ' => 27,
  11713. 'ࣱ' => 28,
  11714. 'ࣲ' => 29,
  11715. 'ࣳ' => 230,
  11716. 'ࣴ' => 230,
  11717. 'ࣵ' => 230,
  11718. 'ࣶ' => 220,
  11719. 'ࣷ' => 230,
  11720. 'ࣸ' => 230,
  11721. 'ࣹ' => 220,
  11722. 'ࣺ' => 220,
  11723. 'ࣻ' => 230,
  11724. 'ࣼ' => 230,
  11725. 'ࣽ' => 230,
  11726. 'ࣾ' => 230,
  11727. 'ࣿ' => 230,
  11728. '़' => 7,
  11729. '�' => 9,
  11730. '॑' => 230,
  11731. '॒' => 220,
  11732. '॓' => 230,
  11733. '॔' => 230,
  11734. '়' => 7,
  11735. '�' => 9,
  11736. 'à§¾' => 230,
  11737. '਼' => 7,
  11738. '�' => 9,
  11739. '઼' => 7,
  11740. '�' => 9,
  11741. '଼' => 7,
  11742. 'à­�' => 9,
  11743. '�' => 9,
  11744. '�' => 9,
  11745. 'ౕ' => 84,
  11746. 'à±–' => 91,
  11747. '಼' => 7,
  11748. '�' => 9,
  11749. 'à´»' => 9,
  11750. 'à´¼' => 9,
  11751. '�' => 9,
  11752. 'à·Š' => 9,
  11753. 'ุ' => 103,
  11754. 'ู' => 103,
  11755. 'ฺ' => 9,
  11756. '่' => 107,
  11757. '้' => 107,
  11758. '๊' => 107,
  11759. '๋' => 107,
  11760. 'ຸ' => 118,
  11761. 'ູ' => 118,
  11762. '຺' => 9,
  11763. '່' => 122,
  11764. '້' => 122,
  11765. '໊' => 122,
  11766. '໋' => 122,
  11767. '༘' => 220,
  11768. '༙' => 220,
  11769. '༵' => 220,
  11770. '༷' => 220,
  11771. '༹' => 216,
  11772. 'ཱ' => 129,
  11773. 'ི' => 130,
  11774. 'ུ' => 132,
  11775. 'ེ' => 130,
  11776. 'ཻ' => 130,
  11777. 'ོ' => 130,
  11778. 'ཽ' => 130,
  11779. 'ྀ' => 130,
  11780. 'ྂ' => 230,
  11781. 'ྃ' => 230,
  11782. '྄' => 9,
  11783. '྆' => 230,
  11784. '྇' => 230,
  11785. '࿆' => 220,
  11786. '့' => 7,
  11787. '္' => 9,
  11788. '်' => 9,
  11789. '�' => 220,
  11790. '�' => 230,
  11791. '�' => 230,
  11792. '�' => 230,
  11793. '᜔' => 9,
  11794. '᜴' => 9,
  11795. '្' => 9,
  11796. '�' => 230,
  11797. 'ᢩ' => 228,
  11798. '᤹' => 222,
  11799. '᤺' => 230,
  11800. '᤻' => 220,
  11801. 'ᨗ' => 230,
  11802. 'ᨘ' => 220,
  11803. 'á© ' => 9,
  11804. '᩵' => 230,
  11805. 'á©¶' => 230,
  11806. 'á©·' => 230,
  11807. '᩸' => 230,
  11808. '᩹' => 230,
  11809. '᩺' => 230,
  11810. 'á©»' => 230,
  11811. '᩼' => 230,
  11812. 'á©¿' => 220,
  11813. '᪰' => 230,
  11814. '᪱' => 230,
  11815. '᪲' => 230,
  11816. '᪳' => 230,
  11817. '᪴' => 230,
  11818. '᪵' => 220,
  11819. '᪶' => 220,
  11820. '᪷' => 220,
  11821. '᪸' => 220,
  11822. '᪹' => 220,
  11823. '᪺' => 220,
  11824. '᪻' => 230,
  11825. '᪼' => 230,
  11826. '᪽' => 220,
  11827. 'ᪿ' => 220,
  11828. 'á«€' => 220,
  11829. '᬴' => 7,
  11830. 'á­„' => 9,
  11831. 'á­«' => 230,
  11832. 'á­¬' => 220,
  11833. 'á­­' => 230,
  11834. 'á­®' => 230,
  11835. 'á­¯' => 230,
  11836. 'á­°' => 230,
  11837. 'á­±' => 230,
  11838. 'á­²' => 230,
  11839. 'á­³' => 230,
  11840. '᮪' => 9,
  11841. '᮫' => 9,
  11842. '᯦' => 7,
  11843. '᯲' => 9,
  11844. '᯳' => 9,
  11845. 'á°·' => 7,
  11846. '�' => 230,
  11847. '᳑' => 230,
  11848. 'á³’' => 230,
  11849. 'á³”' => 1,
  11850. '᳕' => 220,
  11851. 'á³–' => 220,
  11852. 'á³—' => 220,
  11853. '᳘' => 220,
  11854. 'á³™' => 220,
  11855. '᳚' => 230,
  11856. 'á³›' => 230,
  11857. '᳜' => 220,
  11858. '�' => 220,
  11859. '᳞' => 220,
  11860. '᳟' => 220,
  11861. 'á³ ' => 230,
  11862. 'á³¢' => 1,
  11863. 'á³£' => 1,
  11864. '᳤' => 1,
  11865. 'á³¥' => 1,
  11866. '᳦' => 1,
  11867. 'á³§' => 1,
  11868. '᳨' => 1,
  11869. 'á³­' => 220,
  11870. 'á³´' => 230,
  11871. '᳸' => 230,
  11872. 'á³¹' => 230,
  11873. 'á·€' => 230,
  11874. 'á·�' => 230,
  11875. 'á·‚' => 220,
  11876. 'á·ƒ' => 230,
  11877. 'á·„' => 230,
  11878. 'á·…' => 230,
  11879. 'á·†' => 230,
  11880. 'á·‡' => 230,
  11881. 'á·ˆ' => 230,
  11882. 'á·‰' => 230,
  11883. 'á·Š' => 220,
  11884. 'á·‹' => 230,
  11885. '᷌' => 230,
  11886. 'á·�' => 234,
  11887. 'á·Ž' => 214,
  11888. 'á·�' => 220,
  11889. 'á·�' => 202,
  11890. 'á·‘' => 230,
  11891. 'á·’' => 230,
  11892. 'á·“' => 230,
  11893. 'á·”' => 230,
  11894. 'á·•' => 230,
  11895. 'á·–' => 230,
  11896. 'á·—' => 230,
  11897. 'á·˜' => 230,
  11898. 'á·™' => 230,
  11899. 'á·š' => 230,
  11900. 'á·›' => 230,
  11901. 'ᷜ' => 230,
  11902. 'á·�' => 230,
  11903. 'á·ž' => 230,
  11904. 'á·Ÿ' => 230,
  11905. 'á· ' => 230,
  11906. 'á·¡' => 230,
  11907. 'á·¢' => 230,
  11908. 'á·£' => 230,
  11909. 'á·¤' => 230,
  11910. 'á·¥' => 230,
  11911. 'á·¦' => 230,
  11912. 'á·§' => 230,
  11913. 'á·¨' => 230,
  11914. 'á·©' => 230,
  11915. 'á·ª' => 230,
  11916. 'á·«' => 230,
  11917. 'á·¬' => 230,
  11918. 'á·­' => 230,
  11919. 'á·®' => 230,
  11920. 'á·¯' => 230,
  11921. 'á·°' => 230,
  11922. 'á·±' => 230,
  11923. 'á·²' => 230,
  11924. 'á·³' => 230,
  11925. 'á·´' => 230,
  11926. 'á·µ' => 230,
  11927. 'á·¶' => 232,
  11928. 'á··' => 228,
  11929. 'á·¸' => 228,
  11930. 'á·¹' => 220,
  11931. 'á·»' => 230,
  11932. 'á·¼' => 233,
  11933. 'á·½' => 220,
  11934. 'á·¾' => 230,
  11935. 'á·¿' => 220,
  11936. '�' => 230,
  11937. '⃑' => 230,
  11938. '⃒' => 1,
  11939. '⃓' => 1,
  11940. '⃔' => 230,
  11941. '⃕' => 230,
  11942. '⃖' => 230,
  11943. '⃗' => 230,
  11944. '⃘' => 1,
  11945. '⃙' => 1,
  11946. '⃚' => 1,
  11947. '⃛' => 230,
  11948. '⃜' => 230,
  11949. '⃡' => 230,
  11950. '⃥' => 1,
  11951. '⃦' => 1,
  11952. '⃧' => 230,
  11953. '⃨' => 220,
  11954. '⃩' => 230,
  11955. '⃪' => 1,
  11956. '⃫' => 1,
  11957. '⃬' => 220,
  11958. '⃭' => 220,
  11959. '⃮' => 220,
  11960. '⃯' => 220,
  11961. '⃰' => 230,
  11962. '⳯' => 230,
  11963. 'â³°' => 230,
  11964. 'â³±' => 230,
  11965. '⵿' => 9,
  11966. 'â· ' => 230,
  11967. 'â·¡' => 230,
  11968. 'â·¢' => 230,
  11969. 'â·£' => 230,
  11970. 'â·¤' => 230,
  11971. 'â·¥' => 230,
  11972. 'â·¦' => 230,
  11973. 'â·§' => 230,
  11974. 'â·¨' => 230,
  11975. 'â·©' => 230,
  11976. 'â·ª' => 230,
  11977. 'â·«' => 230,
  11978. 'â·¬' => 230,
  11979. 'â·­' => 230,
  11980. 'â·®' => 230,
  11981. 'â·¯' => 230,
  11982. 'â·°' => 230,
  11983. 'â·±' => 230,
  11984. 'â·²' => 230,
  11985. 'â·³' => 230,
  11986. 'â·´' => 230,
  11987. 'â·µ' => 230,
  11988. 'â·¶' => 230,
  11989. 'â··' => 230,
  11990. 'â·¸' => 230,
  11991. 'â·¹' => 230,
  11992. 'â·º' => 230,
  11993. 'â·»' => 230,
  11994. 'â·¼' => 230,
  11995. 'â·½' => 230,
  11996. 'â·¾' => 230,
  11997. 'â·¿' => 230,
  11998. '〪' => 218,
  11999. '〫' => 228,
  12000. '〬' => 232,
  12001. '〭' => 222,
  12002. '〮' => 224,
  12003. '〯' => 224,
  12004. 'ã‚™' => 8,
  12005. '゚' => 8,
  12006. '꙯' => 230,
  12007. 'ê™´' => 230,
  12008. 'ꙵ' => 230,
  12009. 'ê™¶' => 230,
  12010. 'ê™·' => 230,
  12011. 'ꙸ' => 230,
  12012. 'ꙹ' => 230,
  12013. 'ꙺ' => 230,
  12014. 'ê™»' => 230,
  12015. '꙼' => 230,
  12016. '꙽' => 230,
  12017. 'êšž' => 230,
  12018. 'ꚟ' => 230,
  12019. 'ê›°' => 230,
  12020. 'ê›±' => 230,
  12021. 'ê †' => 9,
  12022. 'ê ¬' => 9,
  12023. '꣄' => 9,
  12024. '꣠' => 230,
  12025. '꣡' => 230,
  12026. '꣢' => 230,
  12027. '꣣' => 230,
  12028. '꣤' => 230,
  12029. '꣥' => 230,
  12030. '꣦' => 230,
  12031. '꣧' => 230,
  12032. '꣨' => 230,
  12033. '꣩' => 230,
  12034. '꣪' => 230,
  12035. '꣫' => 230,
  12036. '꣬' => 230,
  12037. '꣭' => 230,
  12038. '꣮' => 230,
  12039. '꣯' => 230,
  12040. '꣰' => 230,
  12041. '꣱' => 230,
  12042. '꤫' => 220,
  12043. '꤬' => 220,
  12044. '꤭' => 220,
  12045. '꥓' => 9,
  12046. '꦳' => 7,
  12047. 'ê§€' => 9,
  12048. 'ꪰ' => 230,
  12049. 'ꪲ' => 230,
  12050. 'ꪳ' => 230,
  12051. 'ꪴ' => 220,
  12052. 'ꪷ' => 230,
  12053. 'ꪸ' => 230,
  12054. 'ꪾ' => 230,
  12055. '꪿' => 230,
  12056. '�' => 230,
  12057. 'ê«¶' => 9,
  12058. '꯭' => 9,
  12059. 'ﬞ' => 26,
  12060. '︠' => 230,
  12061. '︡' => 230,
  12062. '︢' => 230,
  12063. '︣' => 230,
  12064. '︤' => 230,
  12065. '︥' => 230,
  12066. '︦' => 230,
  12067. '︧' => 220,
  12068. '︨' => 220,
  12069. '︩' => 220,
  12070. '︪' => 220,
  12071. '︫' => 220,
  12072. '︬' => 220,
  12073. '︭' => 220,
  12074. '︮' => 230,
  12075. '︯' => 230,
  12076. '�' => 220,
  12077. '�' => 220,
  12078. '�' => 230,
  12079. '�' => 230,
  12080. '�' => 230,
  12081. '�' => 230,
  12082. '�' => 230,
  12083. '�' => 220,
  12084. '�' => 230,
  12085. '�' => 230,
  12086. '�' => 1,
  12087. '�' => 220,
  12088. '�' => 9,
  12089. '�' => 230,
  12090. '�' => 220,
  12091. '�' => 230,
  12092. '�' => 230,
  12093. '�' => 230,
  12094. '�' => 230,
  12095. '�' => 230,
  12096. '�' => 230,
  12097. '�' => 220,
  12098. '�' => 220,
  12099. '�' => 230,
  12100. '�' => 230,
  12101. '�' => 230,
  12102. '�' => 220,
  12103. '�' => 230,
  12104. '�' => 220,
  12105. '�' => 220,
  12106. '�' => 220,
  12107. '�' => 220,
  12108. '�' => 9,
  12109. '�' => 9,
  12110. 'ð‘‚¹' => 9,
  12111. '𑂺' => 7,
  12112. 'ð‘„€' => 230,
  12113. '�' => 230,
  12114. 'ð‘„‚' => 230,
  12115. 'ð‘„³' => 9,
  12116. 'ð‘„´' => 9,
  12117. 'ð‘…³' => 7,
  12118. '𑇀' => 9,
  12119. '𑇊' => 7,
  12120. '𑈵' => 9,
  12121. '𑈶' => 7,
  12122. 'ð‘‹©' => 7,
  12123. '𑋪' => 9,
  12124. '𑌻' => 7,
  12125. '𑌼' => 7,
  12126. '�' => 9,
  12127. '�' => 230,
  12128. '�' => 230,
  12129. '�' => 230,
  12130. '�' => 230,
  12131. '�' => 230,
  12132. '�' => 230,
  12133. '�' => 230,
  12134. '�' => 230,
  12135. '�' => 230,
  12136. '�' => 230,
  12137. '�' => 230,
  12138. '�' => 230,
  12139. 'ð‘‘‚' => 9,
  12140. '𑑆' => 7,
  12141. 'ð‘‘ž' => 230,
  12142. 'ð‘“‚' => 9,
  12143. '𑓃' => 7,
  12144. 'ð‘–¿' => 9,
  12145. 'ð‘—€' => 7,
  12146. '𑘿' => 9,
  12147. '𑚶' => 9,
  12148. '𑚷' => 7,
  12149. '𑜫' => 9,
  12150. 'ð‘ ¹' => 9,
  12151. 'ð‘ º' => 7,
  12152. '𑤽' => 9,
  12153. '𑤾' => 9,
  12154. '𑥃' => 7,
  12155. 'ð‘§ ' => 9,
  12156. '𑨴' => 9,
  12157. '𑩇' => 9,
  12158. '𑪙' => 9,
  12159. 'ð‘°¿' => 9,
  12160. '𑵂' => 7,
  12161. '𑵄' => 9,
  12162. '𑵅' => 9,
  12163. 'ð‘¶—' => 9,
  12164. 'ð–«°' => 1,
  12165. 'ð–«±' => 1,
  12166. 'ð–«²' => 1,
  12167. 'ð–«³' => 1,
  12168. 'ð–«´' => 1,
  12169. 'ð–¬°' => 230,
  12170. '𖬱' => 230,
  12171. '𖬲' => 230,
  12172. '𖬳' => 230,
  12173. 'ð–¬´' => 230,
  12174. '𖬵' => 230,
  12175. '𖬶' => 230,
  12176. 'ð–¿°' => 6,
  12177. 'ð–¿±' => 6,
  12178. '𛲞' => 1,
  12179. '�' => 216,
  12180. '�' => 216,
  12181. '�' => 1,
  12182. '�' => 1,
  12183. '�' => 1,
  12184. '�' => 226,
  12185. '�' => 216,
  12186. '�' => 216,
  12187. '�' => 216,
  12188. '�' => 216,
  12189. '�' => 216,
  12190. '�' => 220,
  12191. '�' => 220,
  12192. '�' => 220,
  12193. '�' => 220,
  12194. '�' => 220,
  12195. '�' => 220,
  12196. '�' => 220,
  12197. '�' => 220,
  12198. '�' => 230,
  12199. '�' => 230,
  12200. '�' => 230,
  12201. '�' => 230,
  12202. '�' => 230,
  12203. '�' => 220,
  12204. '�' => 220,
  12205. '�' => 230,
  12206. '�' => 230,
  12207. '�' => 230,
  12208. '�' => 230,
  12209. '�' => 230,
  12210. '�' => 230,
  12211. '�' => 230,
  12212. '𞀀' => 230,
  12213. '�' => 230,
  12214. '𞀂' => 230,
  12215. '𞀃' => 230,
  12216. '𞀄' => 230,
  12217. '𞀅' => 230,
  12218. '𞀆' => 230,
  12219. '𞀈' => 230,
  12220. '𞀉' => 230,
  12221. '𞀊' => 230,
  12222. '𞀋' => 230,
  12223. '𞀌' => 230,
  12224. '�' => 230,
  12225. '𞀎' => 230,
  12226. '�' => 230,
  12227. '�' => 230,
  12228. '𞀑' => 230,
  12229. '𞀒' => 230,
  12230. '𞀓' => 230,
  12231. '𞀔' => 230,
  12232. '𞀕' => 230,
  12233. '𞀖' => 230,
  12234. '𞀗' => 230,
  12235. '𞀘' => 230,
  12236. '𞀛' => 230,
  12237. '𞀜' => 230,
  12238. '�' => 230,
  12239. '𞀞' => 230,
  12240. '𞀟' => 230,
  12241. '𞀠' => 230,
  12242. '𞀡' => 230,
  12243. '𞀣' => 230,
  12244. '𞀤' => 230,
  12245. '𞀦' => 230,
  12246. '𞀧' => 230,
  12247. '𞀨' => 230,
  12248. '𞀩' => 230,
  12249. '𞀪' => 230,
  12250. 'ðž„°' => 230,
  12251. '𞄱' => 230,
  12252. '𞄲' => 230,
  12253. '𞄳' => 230,
  12254. 'ðž„´' => 230,
  12255. '𞄵' => 230,
  12256. 'ðž„¶' => 230,
  12257. '𞋬' => 230,
  12258. 'ðž‹­' => 230,
  12259. 'ðž‹®' => 230,
  12260. '𞋯' => 230,
  12261. '�' => 220,
  12262. '𞣑' => 220,
  12263. '𞣒' => 220,
  12264. '𞣓' => 220,
  12265. '𞣔' => 220,
  12266. '𞣕' => 220,
  12267. '𞣖' => 220,
  12268. '𞥄' => 230,
  12269. '𞥅' => 230,
  12270. '𞥆' => 230,
  12271. '𞥇' => 230,
  12272. '𞥈' => 230,
  12273. '𞥉' => 230,
  12274. '𞥊' => 7,
  12275. );
  12276. <?php
  12277. return array (
  12278. 'À' => 'À',
  12279. '�' => 'A�',
  12280. 'Â' => 'Â',
  12281. 'Ã' => 'Ã',
  12282. 'Ä' => 'Ä',
  12283. 'Ã…' => 'AÌŠ',
  12284. 'Ç' => 'Ç',
  12285. 'È' => 'È',
  12286. 'É' => 'E�',
  12287. 'Ê' => 'Ê',
  12288. 'Ë' => 'Ë',
  12289. 'Ì' => 'Ì',
  12290. '�' => 'I�',
  12291. 'ÃŽ' => 'IÌ‚',
  12292. '�' => 'Ï',
  12293. 'Ñ' => 'Ñ',
  12294. 'Ã’' => 'OÌ€',
  12295. 'Ó' => 'O�',
  12296. 'Ô' => 'Ô',
  12297. 'Õ' => 'Õ',
  12298. 'Ö' => 'Ö',
  12299. 'Ù' => 'Ù',
  12300. 'Ú' => 'U�',
  12301. 'Û' => 'Û',
  12302. 'Ü' => 'Ü',
  12303. '�' => 'Y�',
  12304. 'à' => 'à',
  12305. 'á' => 'a�',
  12306. 'â' => 'â',
  12307. 'ã' => 'ã',
  12308. 'ä' => 'ä',
  12309. 'Ã¥' => 'aÌŠ',
  12310. 'ç' => 'ç',
  12311. 'è' => 'è',
  12312. 'é' => 'e�',
  12313. 'ê' => 'ê',
  12314. 'ë' => 'ë',
  12315. 'ì' => 'ì',
  12316. 'í' => 'i�',
  12317. 'î' => 'î',
  12318. 'ï' => 'ï',
  12319. 'ñ' => 'ñ',
  12320. 'ò' => 'ò',
  12321. 'ó' => 'o�',
  12322. 'ô' => 'ô',
  12323. 'õ' => 'õ',
  12324. 'ö' => 'ö',
  12325. 'ù' => 'ù',
  12326. 'ú' => 'u�',
  12327. 'û' => 'û',
  12328. 'ü' => 'ü',
  12329. 'ý' => 'y�',
  12330. 'ÿ' => 'ÿ',
  12331. 'Ä€' => 'AÌ„',
  12332. '�' => 'ā',
  12333. 'Ă' => 'Ă',
  12334. 'ă' => 'ă',
  12335. 'Ą' => 'Ą',
  12336. 'ą' => 'ą',
  12337. 'Ć' => 'C�',
  12338. 'ć' => 'c�',
  12339. 'Ĉ' => 'Ĉ',
  12340. 'ĉ' => 'ĉ',
  12341. 'Ċ' => 'Ċ',
  12342. 'ċ' => 'ċ',
  12343. 'Č' => 'Č',
  12344. '�' => 'č',
  12345. 'Ď' => 'Ď',
  12346. '�' => 'ď',
  12347. 'Ä’' => 'EÌ„',
  12348. 'ē' => 'ē',
  12349. 'Ĕ' => 'Ĕ',
  12350. 'ĕ' => 'ĕ',
  12351. 'Ė' => 'Ė',
  12352. 'ė' => 'ė',
  12353. 'Ę' => 'Ę',
  12354. 'ę' => 'ę',
  12355. 'Ě' => 'Ě',
  12356. 'ě' => 'ě',
  12357. 'Ĝ' => 'Ĝ',
  12358. '�' => 'ĝ',
  12359. 'Ğ' => 'Ğ',
  12360. 'ğ' => 'ğ',
  12361. 'Ġ' => 'Ġ',
  12362. 'ġ' => 'ġ',
  12363. 'Ģ' => 'Ģ',
  12364. 'ģ' => 'ģ',
  12365. 'Ĥ' => 'Ĥ',
  12366. 'ĥ' => 'ĥ',
  12367. 'Ĩ' => 'Ĩ',
  12368. 'ĩ' => 'ĩ',
  12369. 'Ī' => 'Ī',
  12370. 'ī' => 'ī',
  12371. 'Ĭ' => 'Ĭ',
  12372. 'ĭ' => 'ĭ',
  12373. 'Į' => 'Į',
  12374. 'į' => 'į',
  12375. 'İ' => 'İ',
  12376. 'Ä´' => 'JÌ‚',
  12377. 'ĵ' => 'ĵ',
  12378. 'Ķ' => 'Ķ',
  12379. 'ķ' => 'ķ',
  12380. 'Ĺ' => 'L�',
  12381. 'ĺ' => 'l�',
  12382. 'Ļ' => 'Ļ',
  12383. 'ļ' => 'ļ',
  12384. 'Ľ' => 'Ľ',
  12385. 'ľ' => 'ľ',
  12386. 'Ń' => 'N�',
  12387. 'ń' => 'n�',
  12388. 'Ņ' => 'Ņ',
  12389. 'ņ' => 'ņ',
  12390. 'Ň' => 'Ň',
  12391. 'ň' => 'ň',
  12392. 'Ō' => 'Ō',
  12393. '�' => 'ō',
  12394. 'Ŏ' => 'Ŏ',
  12395. '�' => 'ŏ',
  12396. '�' => 'Ő',
  12397. 'ő' => 'ő',
  12398. 'Ŕ' => 'R�',
  12399. 'ŕ' => 'r�',
  12400. 'Ŗ' => 'Ŗ',
  12401. 'ŗ' => 'ŗ',
  12402. 'Ř' => 'Ř',
  12403. 'ř' => 'ř',
  12404. 'Ś' => 'S�',
  12405. 'ś' => 's�',
  12406. 'Ŝ' => 'Ŝ',
  12407. '�' => 'ŝ',
  12408. 'Ş' => 'Ş',
  12409. 'ş' => 'ş',
  12410. 'Š' => 'Š',
  12411. 'š' => 'š',
  12412. 'Ţ' => 'Ţ',
  12413. 'ţ' => 'ţ',
  12414. 'Ť' => 'Ť',
  12415. 'ť' => 'ť',
  12416. 'Ũ' => 'Ũ',
  12417. 'ũ' => 'ũ',
  12418. 'Ū' => 'Ū',
  12419. 'ū' => 'ū',
  12420. 'Ŭ' => 'Ŭ',
  12421. 'ŭ' => 'ŭ',
  12422. 'Å®' => 'UÌŠ',
  12423. 'ů' => 'ů',
  12424. 'Ű' => 'Ű',
  12425. 'ű' => 'ű',
  12426. 'Ų' => 'Ų',
  12427. 'ų' => 'ų',
  12428. 'Å´' => 'WÌ‚',
  12429. 'ŵ' => 'ŵ',
  12430. 'Ŷ' => 'Ŷ',
  12431. 'ŷ' => 'ŷ',
  12432. 'Ÿ' => 'Ÿ',
  12433. 'Ź' => 'Z�',
  12434. 'ź' => 'z�',
  12435. 'Ż' => 'Ż',
  12436. 'ż' => 'ż',
  12437. 'Ž' => 'Ž',
  12438. 'ž' => 'ž',
  12439. 'Æ ' => 'OÌ›',
  12440. 'Æ¡' => 'oÌ›',
  12441. 'Ư' => 'Ư',
  12442. 'ư' => 'ư',
  12443. '�' => 'Ǎ',
  12444. 'ǎ' => 'ǎ',
  12445. '�' => 'Ǐ',
  12446. '�' => 'ǐ',
  12447. 'Ǒ' => 'Ǒ',
  12448. 'ǒ' => 'ǒ',
  12449. 'Ǔ' => 'Ǔ',
  12450. 'ǔ' => 'ǔ',
  12451. 'Ǖ' => 'Ǖ',
  12452. 'ǖ' => 'ǖ',
  12453. 'Ǘ' => 'Ü�',
  12454. 'ǘ' => 'ü�',
  12455. 'Ǚ' => 'Ǚ',
  12456. 'ǚ' => 'ǚ',
  12457. 'Ǜ' => 'Ǜ',
  12458. 'ǜ' => 'ǜ',
  12459. 'Ǟ' => 'Ǟ',
  12460. 'ǟ' => 'ǟ',
  12461. 'Ǡ' => 'Ǡ',
  12462. 'ǡ' => 'ǡ',
  12463. 'Ǣ' => 'Ǣ',
  12464. 'ǣ' => 'ǣ',
  12465. 'Ǧ' => 'Ǧ',
  12466. 'ǧ' => 'ǧ',
  12467. 'Ǩ' => 'Ǩ',
  12468. 'ǩ' => 'ǩ',
  12469. 'Ǫ' => 'Ǫ',
  12470. 'ǫ' => 'ǫ',
  12471. 'Ǭ' => 'Ǭ',
  12472. 'ǭ' => 'ǭ',
  12473. 'Ǯ' => 'Ǯ',
  12474. 'ǯ' => 'ǯ',
  12475. 'ǰ' => 'ǰ',
  12476. 'Ǵ' => 'G�',
  12477. 'ǵ' => 'g�',
  12478. 'Ǹ' => 'Ǹ',
  12479. 'ǹ' => 'ǹ',
  12480. 'Ǻ' => 'Å�',
  12481. 'ǻ' => 'å�',
  12482. 'Ǽ' => 'Æ�',
  12483. 'ǽ' => 'æ�',
  12484. 'Ǿ' => 'Ø�',
  12485. 'ǿ' => 'ø�',
  12486. 'Ȁ' => 'A�',
  12487. '�' => 'a�',
  12488. 'È‚' => 'AÌ‘',
  12489. 'ȃ' => 'ȃ',
  12490. 'Ȅ' => 'E�',
  12491. 'ȅ' => 'e�',
  12492. 'Ȇ' => 'Ȇ',
  12493. 'ȇ' => 'ȇ',
  12494. 'Ȉ' => 'I�',
  12495. 'ȉ' => 'i�',
  12496. 'ÈŠ' => 'IÌ‘',
  12497. 'ȋ' => 'ȋ',
  12498. 'Ȍ' => 'O�',
  12499. '�' => 'o�',
  12500. 'ÈŽ' => 'OÌ‘',
  12501. '�' => 'ȏ',
  12502. '�' => 'R�',
  12503. 'ȑ' => 'r�',
  12504. 'È’' => 'RÌ‘',
  12505. 'ȓ' => 'ȓ',
  12506. 'Ȕ' => 'U�',
  12507. 'ȕ' => 'u�',
  12508. 'È–' => 'UÌ‘',
  12509. 'ȗ' => 'ȗ',
  12510. 'Ș' => 'Ș',
  12511. 'ș' => 'ș',
  12512. 'Ț' => 'Ț',
  12513. 'ț' => 'ț',
  12514. 'Ȟ' => 'Ȟ',
  12515. 'ȟ' => 'ȟ',
  12516. 'Ȧ' => 'Ȧ',
  12517. 'ȧ' => 'ȧ',
  12518. 'Ȩ' => 'Ȩ',
  12519. 'ȩ' => 'ȩ',
  12520. 'Ȫ' => 'Ȫ',
  12521. 'ȫ' => 'ȫ',
  12522. 'Ȭ' => 'Ȭ',
  12523. 'ȭ' => 'ȭ',
  12524. 'Ȯ' => 'Ȯ',
  12525. 'ȯ' => 'ȯ',
  12526. 'Ȱ' => 'Ȱ',
  12527. 'ȱ' => 'ȱ',
  12528. 'Ȳ' => 'Ȳ',
  12529. 'ȳ' => 'ȳ',
  12530. 'Í€' => 'Ì€',
  12531. '�' => '�',
  12532. '̓' => '̓',
  12533. '̈́' => '̈�',
  12534. 'ʹ' => 'ʹ',
  12535. ';' => ';',
  12536. '΅' => '¨�',
  12537. 'Ά' => 'Α�',
  12538. '·' => '·',
  12539. 'Έ' => 'Ε�',
  12540. 'Ή' => 'Η�',
  12541. 'Ί' => 'Ι�',
  12542. 'Ό' => 'Ο�',
  12543. 'Ύ' => 'Υ�',
  12544. '�' => 'Ω�',
  12545. '�' => 'ϊ�',
  12546. 'Ϊ' => 'Ϊ',
  12547. 'Ϋ' => 'Ϋ',
  12548. 'ά' => 'α�',
  12549. 'έ' => 'ε�',
  12550. 'ή' => 'η�',
  12551. 'ί' => 'ι�',
  12552. 'ΰ' => 'ϋ�',
  12553. 'ϊ' => 'ϊ',
  12554. 'ϋ' => 'ϋ',
  12555. 'ό' => 'ο�',
  12556. '�' => 'υ�',
  12557. 'ώ' => 'ω�',
  12558. 'ϓ' => 'ϒ�',
  12559. 'ϔ' => 'ϔ',
  12560. 'Ѐ' => 'Ѐ',
  12561. '�' => 'Ё',
  12562. 'Ѓ' => 'Г�',
  12563. 'Ї' => 'Ї',
  12564. 'Ќ' => 'К�',
  12565. '�' => 'Ѝ',
  12566. 'Ў' => 'Ў',
  12567. 'Й' => 'Й',
  12568. 'й' => 'й',
  12569. '�' => 'ѐ',
  12570. 'ё' => 'ё',
  12571. 'ѓ' => 'г�',
  12572. 'ї' => 'ї',
  12573. 'ќ' => 'к�',
  12574. '�' => 'ѝ',
  12575. 'ў' => 'ў',
  12576. 'Ѷ' => 'Ѵ�',
  12577. 'ѷ' => 'ѵ�',
  12578. '�' => 'Ӂ',
  12579. 'ӂ' => 'ӂ',
  12580. '�' => '�̆',
  12581. 'ӑ' => 'ӑ',
  12582. 'Ӓ' => '�̈',
  12583. 'ӓ' => 'ӓ',
  12584. 'Ӗ' => 'Ӗ',
  12585. 'ӗ' => 'ӗ',
  12586. 'Ӛ' => 'Ӛ',
  12587. 'ӛ' => 'ӛ',
  12588. 'Ӝ' => 'Ӝ',
  12589. '�' => 'ӝ',
  12590. 'Ӟ' => 'Ӟ',
  12591. 'ӟ' => 'ӟ',
  12592. 'Ӣ' => 'Ӣ',
  12593. 'ӣ' => 'ӣ',
  12594. 'Ӥ' => 'Ӥ',
  12595. 'ӥ' => 'ӥ',
  12596. 'Ӧ' => 'Ӧ',
  12597. 'ӧ' => 'ӧ',
  12598. 'Ӫ' => 'Ӫ',
  12599. 'ӫ' => 'ӫ',
  12600. 'Ӭ' => 'Ӭ',
  12601. 'ӭ' => '�̈',
  12602. 'Ӯ' => 'Ӯ',
  12603. 'ӯ' => 'ӯ',
  12604. 'Ӱ' => 'Ӱ',
  12605. 'ӱ' => 'ӱ',
  12606. 'Ӳ' => 'Ӳ',
  12607. 'ӳ' => 'ӳ',
  12608. 'Ӵ' => 'Ӵ',
  12609. 'ӵ' => 'ӵ',
  12610. 'Ӹ' => 'Ӹ',
  12611. 'ӹ' => 'ӹ',
  12612. 'آ' => 'آ',
  12613. 'أ' => 'أ',
  12614. 'ؤ' => 'ؤ',
  12615. 'إ' => 'إ',
  12616. 'ئ' => 'ئ',
  12617. 'Û€' => 'Û•Ù”',
  12618. 'Û‚' => 'Û�Ù”',
  12619. 'Û“' => 'Û’Ù”',
  12620. 'ऩ' => 'ऩ',
  12621. 'ऱ' => 'ऱ',
  12622. 'ऴ' => 'ऴ',
  12623. 'क़' => 'क़',
  12624. 'ख़' => 'ख़',
  12625. 'ग़' => 'ग़',
  12626. 'ज़' => 'ज़',
  12627. 'ड़' => 'ड़',
  12628. '�' => 'ढ़',
  12629. 'फ़' => 'फ़',
  12630. 'य़' => 'य़',
  12631. 'ো' => 'ো',
  12632. 'ৌ' => 'ৌ',
  12633. 'ড়' => 'ড়',
  12634. '�' => 'ঢ়',
  12635. 'য়' => 'য়',
  12636. 'ਲ਼' => 'ਲ਼',
  12637. 'ਸ਼' => 'ਸ਼',
  12638. 'ਖ਼' => 'ਖ਼',
  12639. 'ਗ਼' => 'ਗ਼',
  12640. 'ਜ਼' => 'ਜ਼',
  12641. 'ਫ਼' => 'ਫ਼',
  12642. 'ୈ' => 'ୈ',
  12643. 'ୋ' => 'ୋ',
  12644. 'ୌ' => 'ୌ',
  12645. 'ଡ଼' => 'ଡ଼',
  12646. '�' => 'ଢ଼',
  12647. 'ஔ' => 'ஔ',
  12648. 'ொ' => 'ொ',
  12649. 'ோ' => 'ோ',
  12650. 'ௌ' => 'ௌ',
  12651. 'ై' => 'ై',
  12652. 'ೀ' => 'ೀ',
  12653. 'ೇ' => 'ೇ',
  12654. 'ೈ' => 'ೈ',
  12655. 'ೊ' => 'ೊ',
  12656. 'ೋ' => 'ೋ',
  12657. 'ൊ' => 'ൊ',
  12658. 'ോ' => 'ോ',
  12659. 'ൌ' => 'ൌ',
  12660. 'ේ' => 'ේ',
  12661. 'ො' => 'ෙ�',
  12662. '�' => 'ෙ�්',
  12663. 'ෞ' => 'ෞ',
  12664. 'གྷ' => 'གྷ',
  12665. '�' => 'ཌྷ',
  12666. 'དྷ' => 'དྷ',
  12667. 'བྷ' => 'བྷ',
  12668. 'ཛྷ' => 'ཛྷ',
  12669. 'ཀྵ' => 'ཀྵ',
  12670. 'ཱི' => 'ཱི',
  12671. 'ཱུ' => 'ཱུ',
  12672. 'ྲྀ' => 'ྲྀ',
  12673. 'ླྀ' => 'ླྀ',
  12674. '�' => 'ཱྀ',
  12675. 'ྒྷ' => 'ྒྷ',
  12676. '�' => 'ྜྷ',
  12677. 'ྡྷ' => 'ྡྷ',
  12678. 'ྦྷ' => 'ྦྷ',
  12679. 'ྫྷ' => 'ྫྷ',
  12680. 'ྐྵ' => '�ྵ',
  12681. 'ဦ' => 'ဦ',
  12682. 'ᬆ' => 'ᬆ',
  12683. 'ᬈ' => 'ᬈ',
  12684. 'ᬊ' => 'ᬊ',
  12685. 'ᬌ' => 'ᬌ',
  12686. 'ᬎ' => '�ᬵ',
  12687. 'ᬒ' => 'ᬒ',
  12688. 'ᬻ' => 'ᬻ',
  12689. 'ᬽ' => 'ᬽ',
  12690. 'ᭀ' => 'ᭀ',
  12691. '�' => 'ᭁ',
  12692. 'ᭃ' => 'ᭃ',
  12693. 'Ḁ' => 'Ḁ',
  12694. '�' => 'ḁ',
  12695. 'Ḃ' => 'Ḃ',
  12696. 'ḃ' => 'ḃ',
  12697. 'Ḅ' => 'Ḅ',
  12698. 'ḅ' => 'ḅ',
  12699. 'Ḇ' => 'Ḇ',
  12700. 'ḇ' => 'ḇ',
  12701. 'Ḉ' => 'Ç�',
  12702. 'ḉ' => 'ç�',
  12703. 'Ḋ' => 'Ḋ',
  12704. 'ḋ' => 'ḋ',
  12705. 'Ḍ' => 'Ḍ',
  12706. '�' => 'ḍ',
  12707. 'Ḏ' => 'Ḏ',
  12708. '�' => 'ḏ',
  12709. '�' => 'Ḑ',
  12710. 'ḑ' => 'ḑ',
  12711. 'Ḓ' => 'Ḓ',
  12712. 'ḓ' => 'ḓ',
  12713. 'Ḕ' => 'Ḕ',
  12714. 'ḕ' => 'ḕ',
  12715. 'Ḗ' => 'Ē�',
  12716. 'ḗ' => 'ē�',
  12717. 'Ḙ' => 'Ḙ',
  12718. 'ḙ' => 'ḙ',
  12719. 'Ḛ' => 'Ḛ',
  12720. 'ḛ' => 'ḛ',
  12721. 'Ḝ' => 'Ḝ',
  12722. '�' => 'ḝ',
  12723. 'Ḟ' => 'Ḟ',
  12724. 'ḟ' => 'ḟ',
  12725. 'Ḡ' => 'Ḡ',
  12726. 'ḡ' => 'ḡ',
  12727. 'Ḣ' => 'Ḣ',
  12728. 'ḣ' => 'ḣ',
  12729. 'Ḥ' => 'Ḥ',
  12730. 'ḥ' => 'ḥ',
  12731. 'Ḧ' => 'Ḧ',
  12732. 'ḧ' => 'ḧ',
  12733. 'Ḩ' => 'Ḩ',
  12734. 'ḩ' => 'ḩ',
  12735. 'Ḫ' => 'Ḫ',
  12736. 'ḫ' => 'ḫ',
  12737. 'Ḭ' => 'Ḭ',
  12738. 'ḭ' => 'ḭ',
  12739. 'Ḯ' => 'Ï�',
  12740. 'ḯ' => 'ï�',
  12741. 'Ḱ' => 'K�',
  12742. 'ḱ' => 'k�',
  12743. 'Ḳ' => 'Ḳ',
  12744. 'ḳ' => 'ḳ',
  12745. 'Ḵ' => 'Ḵ',
  12746. 'ḵ' => 'ḵ',
  12747. 'Ḷ' => 'Ḷ',
  12748. 'ḷ' => 'ḷ',
  12749. 'Ḹ' => 'Ḹ',
  12750. 'ḹ' => 'ḹ',
  12751. 'Ḻ' => 'Ḻ',
  12752. 'ḻ' => 'ḻ',
  12753. 'Ḽ' => 'Ḽ',
  12754. 'ḽ' => 'ḽ',
  12755. 'Ḿ' => 'M�',
  12756. 'ḿ' => 'm�',
  12757. 'Ṁ' => 'Ṁ',
  12758. '�' => 'ṁ',
  12759. 'Ṃ' => 'Ṃ',
  12760. 'ṃ' => 'ṃ',
  12761. 'Ṅ' => 'Ṅ',
  12762. 'ṅ' => 'ṅ',
  12763. 'Ṇ' => 'Ṇ',
  12764. 'ṇ' => 'ṇ',
  12765. 'Ṉ' => 'Ṉ',
  12766. 'ṉ' => 'ṉ',
  12767. 'Ṋ' => 'Ṋ',
  12768. 'ṋ' => 'ṋ',
  12769. 'Ṍ' => 'Õ�',
  12770. '�' => 'õ�',
  12771. 'Ṏ' => 'Ṏ',
  12772. '�' => 'ṏ',
  12773. '�' => 'Ṑ',
  12774. 'ṑ' => 'ṑ',
  12775. 'Ṓ' => 'Ō�',
  12776. 'ṓ' => 'ō�',
  12777. 'Ṕ' => 'P�',
  12778. 'ṕ' => 'p�',
  12779. 'Ṗ' => 'Ṗ',
  12780. 'ṗ' => 'ṗ',
  12781. 'Ṙ' => 'Ṙ',
  12782. 'ṙ' => 'ṙ',
  12783. 'Ṛ' => 'Ṛ',
  12784. 'ṛ' => 'ṛ',
  12785. 'Ṝ' => 'Ṝ',
  12786. '�' => 'ṝ',
  12787. 'Ṟ' => 'Ṟ',
  12788. 'ṟ' => 'ṟ',
  12789. 'Ṡ' => 'Ṡ',
  12790. 'ṡ' => 'ṡ',
  12791. 'á¹¢' => 'SÌ£',
  12792. 'ṣ' => 'ṣ',
  12793. 'Ṥ' => 'S�̇',
  12794. 'ṥ' => 's�̇',
  12795. 'Ṧ' => 'Ṧ',
  12796. 'ṧ' => 'ṧ',
  12797. 'Ṩ' => 'Ṩ',
  12798. 'ṩ' => 'ṩ',
  12799. 'Ṫ' => 'Ṫ',
  12800. 'ṫ' => 'ṫ',
  12801. 'Ṭ' => 'Ṭ',
  12802. 'ṭ' => 'ṭ',
  12803. 'Ṯ' => 'Ṯ',
  12804. 'ṯ' => 'ṯ',
  12805. 'á¹°' => 'TÌ­',
  12806. 'á¹±' => 'tÌ­',
  12807. 'Ṳ' => 'Ṳ',
  12808. 'ṳ' => 'ṳ',
  12809. 'Ṵ' => 'Ṵ',
  12810. 'ṵ' => 'ṵ',
  12811. 'á¹¶' => 'UÌ­',
  12812. 'á¹·' => 'uÌ­',
  12813. 'Ṹ' => 'Ũ�',
  12814. 'ṹ' => 'ũ�',
  12815. 'Ṻ' => 'Ṻ',
  12816. 'ṻ' => 'ṻ',
  12817. 'Ṽ' => 'Ṽ',
  12818. 'ṽ' => 'ṽ',
  12819. 'á¹¾' => 'VÌ£',
  12820. 'ṿ' => 'ṿ',
  12821. 'Ẁ' => 'Ẁ',
  12822. '�' => 'ẁ',
  12823. 'Ẃ' => 'W�',
  12824. 'ẃ' => 'w�',
  12825. 'Ẅ' => 'Ẅ',
  12826. 'ẅ' => 'ẅ',
  12827. 'Ẇ' => 'Ẇ',
  12828. 'ẇ' => 'ẇ',
  12829. 'Ẉ' => 'Ẉ',
  12830. 'ẉ' => 'ẉ',
  12831. 'Ẋ' => 'Ẋ',
  12832. 'ẋ' => 'ẋ',
  12833. 'Ẍ' => 'Ẍ',
  12834. '�' => 'ẍ',
  12835. 'Ẏ' => 'Ẏ',
  12836. '�' => 'ẏ',
  12837. '�' => 'Ẑ',
  12838. 'ẑ' => 'ẑ',
  12839. 'Ẓ' => 'Ẓ',
  12840. 'ẓ' => 'ẓ',
  12841. 'Ẕ' => 'Ẕ',
  12842. 'ẕ' => 'ẕ',
  12843. 'ẖ' => 'ẖ',
  12844. 'ẗ' => 'ẗ',
  12845. 'ẘ' => 'ẘ',
  12846. 'ẙ' => 'ẙ',
  12847. 'ẛ' => 'ẛ',
  12848. 'Ạ' => 'Ạ',
  12849. 'ạ' => 'ạ',
  12850. 'Ả' => 'Ả',
  12851. 'ả' => 'ả',
  12852. 'Ấ' => 'Â�',
  12853. 'ấ' => 'â�',
  12854. 'Ầ' => 'Ầ',
  12855. 'ầ' => 'ầ',
  12856. 'Ẩ' => 'Ẩ',
  12857. 'ẩ' => 'ẩ',
  12858. 'Ẫ' => 'Ẫ',
  12859. 'ẫ' => 'ẫ',
  12860. 'Ậ' => 'Ậ',
  12861. 'ậ' => 'ậ',
  12862. 'Ắ' => 'Ă�',
  12863. 'ắ' => 'ă�',
  12864. 'Ằ' => 'Ằ',
  12865. 'ằ' => 'ằ',
  12866. 'Ẳ' => 'Ẳ',
  12867. 'ẳ' => 'ẳ',
  12868. 'Ẵ' => 'Ẵ',
  12869. 'ẵ' => 'ẵ',
  12870. 'Ặ' => 'Ặ',
  12871. 'ặ' => 'ặ',
  12872. 'Ẹ' => 'Ẹ',
  12873. 'ẹ' => 'ẹ',
  12874. 'Ẻ' => 'Ẻ',
  12875. 'ẻ' => 'ẻ',
  12876. 'Ẽ' => 'Ẽ',
  12877. 'ẽ' => 'ẽ',
  12878. 'Ế' => 'Ê�',
  12879. 'ế' => 'ê�',
  12880. 'Ề' => 'Ề',
  12881. '�' => 'ề',
  12882. 'Ể' => 'Ể',
  12883. 'ể' => 'ể',
  12884. 'Ễ' => 'Ễ',
  12885. 'ễ' => 'ễ',
  12886. 'Ệ' => 'Ệ',
  12887. 'ệ' => 'ệ',
  12888. 'Ỉ' => 'Ỉ',
  12889. 'ỉ' => 'ỉ',
  12890. 'Ị' => 'Ị',
  12891. 'ị' => 'ị',
  12892. 'Ọ' => 'Ọ',
  12893. '�' => 'ọ',
  12894. 'Ỏ' => 'Ỏ',
  12895. '�' => 'ỏ',
  12896. '�' => 'Ô�',
  12897. 'ố' => 'ô�',
  12898. 'Ồ' => 'Ồ',
  12899. 'ồ' => 'ồ',
  12900. 'Ổ' => 'Ổ',
  12901. 'ổ' => 'ổ',
  12902. 'Ỗ' => 'Ỗ',
  12903. 'ỗ' => 'ỗ',
  12904. 'Ộ' => 'Ộ',
  12905. 'ộ' => 'ộ',
  12906. 'Ớ' => 'Ơ�',
  12907. 'ớ' => 'ơ�',
  12908. 'Ờ' => 'Ờ',
  12909. '�' => 'ờ',
  12910. 'Ở' => 'Ở',
  12911. 'ở' => 'ở',
  12912. 'Ỡ' => 'Ỡ',
  12913. 'ỡ' => 'ỡ',
  12914. 'Ợ' => 'Ợ',
  12915. 'ợ' => 'ợ',
  12916. 'Ụ' => 'Ụ',
  12917. 'ụ' => 'ụ',
  12918. 'Ủ' => 'Ủ',
  12919. 'ủ' => 'ủ',
  12920. 'Ứ' => 'Ư�',
  12921. 'ứ' => 'ư�',
  12922. 'Ừ' => 'Ừ',
  12923. 'ừ' => 'ừ',
  12924. 'Ử' => 'Ử',
  12925. 'ử' => 'ử',
  12926. 'Ữ' => 'Ữ',
  12927. 'ữ' => 'ữ',
  12928. 'Ự' => 'Ự',
  12929. 'ự' => 'ự',
  12930. 'Ỳ' => 'Ỳ',
  12931. 'ỳ' => 'ỳ',
  12932. 'á»´' => 'YÌ£',
  12933. 'ỵ' => 'ỵ',
  12934. 'Ỷ' => 'Ỷ',
  12935. 'ỷ' => 'ỷ',
  12936. 'Ỹ' => 'Ỹ',
  12937. 'ỹ' => 'ỹ',
  12938. 'ἀ' => 'ἀ',
  12939. '�' => 'ἁ',
  12940. 'ἂ' => 'ἂ',
  12941. 'ἃ' => 'ἃ',
  12942. 'ἄ' => 'ἀ�',
  12943. 'ἅ' => 'ἁ�',
  12944. 'ἆ' => 'ἆ',
  12945. 'ἇ' => 'ἇ',
  12946. 'Ἀ' => 'Ἀ',
  12947. 'Ἁ' => 'Ἁ',
  12948. 'Ἂ' => 'Ἂ',
  12949. 'Ἃ' => 'Ἃ',
  12950. 'Ἄ' => 'Ἀ�',
  12951. '�' => 'Ἁ�',
  12952. 'Ἆ' => 'Ἆ',
  12953. '�' => 'Ἇ',
  12954. '�' => 'ἐ',
  12955. 'ἑ' => 'ἑ',
  12956. 'ἒ' => 'ἒ',
  12957. 'ἓ' => 'ἓ',
  12958. 'ἔ' => 'ἐ�',
  12959. 'ἕ' => 'ἑ�',
  12960. 'Ἐ' => 'Ἐ',
  12961. 'Ἑ' => 'Ἑ',
  12962. 'Ἒ' => 'Ἒ',
  12963. 'Ἓ' => 'Ἓ',
  12964. 'Ἔ' => 'Ἐ�',
  12965. '�' => 'Ἑ�',
  12966. 'ἠ' => 'ἠ',
  12967. 'ἡ' => 'ἡ',
  12968. 'ἢ' => 'ἢ',
  12969. 'ἣ' => 'ἣ',
  12970. 'ἤ' => 'ἠ�',
  12971. 'ἥ' => 'ἡ�',
  12972. 'ἦ' => 'ἦ',
  12973. 'ἧ' => 'ἧ',
  12974. 'Ἠ' => 'Ἠ',
  12975. 'Ἡ' => 'Ἡ',
  12976. 'Ἢ' => 'Ἢ',
  12977. 'Ἣ' => 'Ἣ',
  12978. 'Ἤ' => 'Ἠ�',
  12979. 'Ἥ' => 'Ἡ�',
  12980. 'Ἦ' => 'Ἦ',
  12981. 'Ἧ' => 'Ἧ',
  12982. 'ἰ' => 'ἰ',
  12983. 'ἱ' => 'ἱ',
  12984. 'ἲ' => 'ἲ',
  12985. 'ἳ' => 'ἳ',
  12986. 'ἴ' => 'ἰ�',
  12987. 'ἵ' => 'ἱ�',
  12988. 'ἶ' => 'ἶ',
  12989. 'ἷ' => 'ἷ',
  12990. 'Ἰ' => 'Ἰ',
  12991. 'Ἱ' => 'Ἱ',
  12992. 'Ἲ' => 'Ἲ',
  12993. 'Ἳ' => 'Ἳ',
  12994. 'Ἴ' => 'Ἰ�',
  12995. 'Ἵ' => 'Ἱ�',
  12996. 'Ἶ' => 'Ἶ',
  12997. 'Ἷ' => 'Ἷ',
  12998. 'ὀ' => 'ὀ',
  12999. '�' => 'ὁ',
  13000. 'ὂ' => 'ὂ',
  13001. 'ὃ' => 'ὃ',
  13002. 'ὄ' => 'ὀ�',
  13003. 'ὅ' => 'ὁ�',
  13004. 'Ὀ' => 'Ὀ',
  13005. 'Ὁ' => 'Ὁ',
  13006. 'Ὂ' => 'Ὂ',
  13007. 'Ὃ' => 'Ὃ',
  13008. 'Ὄ' => 'Ὀ�',
  13009. '�' => 'Ὁ�',
  13010. '�' => 'ὐ',
  13011. 'ὑ' => 'ὑ',
  13012. 'ὒ' => 'ὒ',
  13013. 'ὓ' => 'ὓ',
  13014. 'ὔ' => 'ὐ�',
  13015. 'ὕ' => 'ὑ�',
  13016. 'ὖ' => 'ὖ',
  13017. 'ὗ' => 'ὗ',
  13018. 'Ὑ' => 'Ὑ',
  13019. 'Ὓ' => 'Ὓ',
  13020. '�' => 'Ὑ�',
  13021. 'Ὗ' => 'Ὗ',
  13022. 'ὠ' => 'ὠ',
  13023. 'ὡ' => 'ὡ',
  13024. 'ὢ' => 'ὢ',
  13025. 'ὣ' => 'ὣ',
  13026. 'ὤ' => 'ὠ�',
  13027. 'ὥ' => 'ὡ�',
  13028. 'ὦ' => 'ὦ',
  13029. 'ὧ' => 'ὧ',
  13030. 'Ὠ' => 'Ὠ',
  13031. 'Ὡ' => 'Ὡ',
  13032. 'Ὢ' => 'Ὢ',
  13033. 'Ὣ' => 'Ὣ',
  13034. 'Ὤ' => 'Ὠ�',
  13035. 'Ὥ' => 'Ὡ�',
  13036. 'Ὦ' => 'Ὦ',
  13037. 'Ὧ' => 'Ὧ',
  13038. 'ὰ' => 'ὰ',
  13039. 'ά' => 'α�',
  13040. 'ὲ' => 'ὲ',
  13041. 'έ' => 'ε�',
  13042. 'ὴ' => 'ὴ',
  13043. 'ή' => 'η�',
  13044. 'ὶ' => 'ὶ',
  13045. 'ί' => 'ι�',
  13046. 'ὸ' => 'ὸ',
  13047. 'ό' => 'ο�',
  13048. 'ὺ' => 'ὺ',
  13049. 'ύ' => 'υ�',
  13050. 'ὼ' => 'ὼ',
  13051. 'ώ' => 'ω�',
  13052. 'ᾀ' => 'ᾀ',
  13053. '�' => 'ᾁ',
  13054. 'ᾂ' => 'ᾂ',
  13055. 'ᾃ' => 'ᾃ',
  13056. 'ᾄ' => 'ἀ�ͅ',
  13057. 'ᾅ' => 'ἁ�ͅ',
  13058. 'ᾆ' => 'ᾆ',
  13059. 'ᾇ' => 'ᾇ',
  13060. 'ᾈ' => 'ᾈ',
  13061. 'ᾉ' => 'ᾉ',
  13062. 'ᾊ' => 'ᾊ',
  13063. 'ᾋ' => 'ᾋ',
  13064. 'ᾌ' => 'Ἀ�ͅ',
  13065. '�' => 'Ἁ�ͅ',
  13066. 'ᾎ' => 'ᾎ',
  13067. '�' => 'ᾏ',
  13068. '�' => 'ᾐ',
  13069. 'ᾑ' => 'ᾑ',
  13070. 'ᾒ' => 'ᾒ',
  13071. 'ᾓ' => 'ᾓ',
  13072. 'ᾔ' => 'ἠ�ͅ',
  13073. 'ᾕ' => 'ἡ�ͅ',
  13074. 'ᾖ' => 'ᾖ',
  13075. 'ᾗ' => 'ᾗ',
  13076. 'ᾘ' => 'ᾘ',
  13077. 'ᾙ' => 'ᾙ',
  13078. 'ᾚ' => 'ᾚ',
  13079. 'ᾛ' => 'ᾛ',
  13080. 'ᾜ' => 'Ἠ�ͅ',
  13081. '�' => 'Ἡ�ͅ',
  13082. 'ᾞ' => 'ᾞ',
  13083. 'ᾟ' => 'ᾟ',
  13084. 'ᾠ' => 'ᾠ',
  13085. 'ᾡ' => 'ᾡ',
  13086. 'ᾢ' => 'ᾢ',
  13087. 'ᾣ' => 'ᾣ',
  13088. 'ᾤ' => 'ὠ�ͅ',
  13089. 'ᾥ' => 'ὡ�ͅ',
  13090. 'ᾦ' => 'ᾦ',
  13091. 'ᾧ' => 'ᾧ',
  13092. 'ᾨ' => 'ᾨ',
  13093. 'ᾩ' => 'ᾩ',
  13094. 'ᾪ' => 'ᾪ',
  13095. 'ᾫ' => 'ᾫ',
  13096. 'ᾬ' => 'Ὠ�ͅ',
  13097. 'ᾭ' => 'Ὡ�ͅ',
  13098. 'ᾮ' => 'ᾮ',
  13099. 'ᾯ' => 'ᾯ',
  13100. 'ᾰ' => 'ᾰ',
  13101. 'ᾱ' => 'ᾱ',
  13102. 'ᾲ' => 'ᾲ',
  13103. 'ᾳ' => 'ᾳ',
  13104. 'ᾴ' => 'α�ͅ',
  13105. 'ᾶ' => 'ᾶ',
  13106. 'ᾷ' => 'ᾷ',
  13107. 'Ᾰ' => 'Ᾰ',
  13108. 'Ᾱ' => 'Ᾱ',
  13109. 'Ὰ' => 'Ὰ',
  13110. 'Ά' => 'Α�',
  13111. 'ᾼ' => 'ᾼ',
  13112. 'ι' => 'ι',
  13113. '�' => '῁',
  13114. 'ῂ' => 'ῂ',
  13115. 'ῃ' => 'ῃ',
  13116. 'ῄ' => 'η�ͅ',
  13117. 'ῆ' => 'ῆ',
  13118. 'ῇ' => 'ῇ',
  13119. 'Ὲ' => 'Ὲ',
  13120. 'Έ' => 'Ε�',
  13121. 'Ὴ' => 'Ὴ',
  13122. 'Ή' => 'Η�',
  13123. 'ῌ' => 'ῌ',
  13124. '�' => '῍',
  13125. '῎' => '᾿�',
  13126. '�' => '῏',
  13127. '�' => 'ῐ',
  13128. 'ῑ' => 'ῑ',
  13129. 'ῒ' => 'ῒ',
  13130. 'ΐ' => 'ϊ�',
  13131. 'ῖ' => 'ῖ',
  13132. 'ῗ' => 'ῗ',
  13133. 'Ῐ' => 'Ῐ',
  13134. 'Ῑ' => 'Ῑ',
  13135. 'Ὶ' => 'Ὶ',
  13136. 'Ί' => 'Ι�',
  13137. '�' => '῝',
  13138. '῞' => '῾�',
  13139. '῟' => '῟',
  13140. 'ῠ' => 'ῠ',
  13141. 'á¿¡' => 'Ï…Ì„',
  13142. 'ῢ' => 'ῢ',
  13143. 'ΰ' => 'ϋ�',
  13144. 'ῤ' => '�̓',
  13145. 'ῥ' => '�̔',
  13146. 'ῦ' => 'ῦ',
  13147. 'ῧ' => 'ῧ',
  13148. 'Ῠ' => 'Ῠ',
  13149. 'Ῡ' => 'Ῡ',
  13150. 'Ὺ' => 'Ὺ',
  13151. 'Ύ' => 'Υ�',
  13152. 'Ῥ' => 'Ῥ',
  13153. '῭' => '῭',
  13154. '΅' => '¨�',
  13155. '`' => '`',
  13156. 'ῲ' => 'ῲ',
  13157. 'ῳ' => 'ῳ',
  13158. 'ῴ' => 'ω�ͅ',
  13159. 'ῶ' => 'ῶ',
  13160. 'ῷ' => 'ῷ',
  13161. 'Ὸ' => 'Ὸ',
  13162. 'Ό' => 'Ο�',
  13163. 'Ὼ' => 'Ὼ',
  13164. 'Ώ' => 'Ω�',
  13165. 'ῼ' => 'ῼ',
  13166. '´' => '´',
  13167. ' ' => ' ',
  13168. '�' => ' ',
  13169. 'Ω' => 'Ω',
  13170. 'K' => 'K',
  13171. 'â„«' => 'AÌŠ',
  13172. '↚' => '�̸',
  13173. '↛' => '↛',
  13174. '↮' => '↮',
  13175. '�' => '�̸',
  13176. '⇎' => '⇎',
  13177. '�' => '⇏',
  13178. '∄' => '∄',
  13179. '∉' => '∉',
  13180. '∌' => '∌',
  13181. '∤' => '∤',
  13182. '∦' => '∦',
  13183. '�' => '≁',
  13184. '≄' => '≄',
  13185. '≇' => '≇',
  13186. '≉' => '≉',
  13187. '≠' => '≠',
  13188. '≢' => '≢',
  13189. '≭' => '�̸',
  13190. '≮' => '≮',
  13191. '≯' => '≯',
  13192. '≰' => '≰',
  13193. '≱' => '≱',
  13194. '≴' => '≴',
  13195. '≵' => '≵',
  13196. '≸' => '≸',
  13197. '≹' => '≹',
  13198. '⊀' => '⊀',
  13199. '�' => '⊁',
  13200. '⊄' => '⊄',
  13201. '⊅' => '⊅',
  13202. '⊈' => '⊈',
  13203. '⊉' => '⊉',
  13204. '⊬' => '⊬',
  13205. '⊭' => '⊭',
  13206. '⊮' => '⊮',
  13207. '⊯' => '⊯',
  13208. '⋠' => '⋠',
  13209. '⋡' => '⋡',
  13210. '⋢' => '⋢',
  13211. '⋣' => '⋣',
  13212. '⋪' => '⋪',
  13213. '⋫' => '⋫',
  13214. '⋬' => '⋬',
  13215. '⋭' => '⋭',
  13216. '〈' => '〈',
  13217. '〉' => '〉',
  13218. '⫝̸' => '�̸',
  13219. '�' => '�゙',
  13220. '�' => '�゙',
  13221. '�' => '�゙',
  13222. '�' => '�゙',
  13223. '�' => '�゙',
  13224. '�' => '�゙',
  13225. '�' => '�゙',
  13226. '�' => '�゙',
  13227. '�' => '�゙',
  13228. '�' => '�゙',
  13229. '�' => '�゙',
  13230. '�' => '�゙',
  13231. '�' => '�゙',
  13232. '�' => '�゙',
  13233. '�' => '�゙',
  13234. '�' => '�゙',
  13235. '�' => '�゚',
  13236. '�' => '�゙',
  13237. '�' => '�゚',
  13238. '�' => '�゙',
  13239. '�' => '�゚',
  13240. '�' => '�゙',
  13241. '�' => '�゚',
  13242. '�' => '�゙',
  13243. '�' => '�゚',
  13244. 'ゔ' => '�゙',
  13245. 'ゞ' => '�゙',
  13246. 'ガ' => 'ガ',
  13247. 'ã‚®' => 'ã‚­ã‚™',
  13248. 'グ' => 'グ',
  13249. 'ゲ' => 'ゲ',
  13250. 'ゴ' => 'ゴ',
  13251. 'ザ' => 'ザ',
  13252. 'ジ' => 'ジ',
  13253. 'ズ' => 'ズ',
  13254. 'ゼ' => 'ゼ',
  13255. 'ゾ' => 'ゾ',
  13256. 'ダ' => 'ダ',
  13257. 'ヂ' => '�゙',
  13258. 'ヅ' => 'ヅ',
  13259. 'デ' => 'デ',
  13260. 'ド' => 'ド',
  13261. '�' => '�゙',
  13262. 'パ' => '�゚',
  13263. 'ビ' => 'ビ',
  13264. 'ピ' => 'ピ',
  13265. 'ブ' => 'ブ',
  13266. 'プ' => 'プ',
  13267. 'ベ' => 'ベ',
  13268. 'ペ' => 'ペ',
  13269. 'ボ' => 'ボ',
  13270. '�' => 'ポ',
  13271. 'ヴ' => 'ヴ',
  13272. 'ヷ' => 'ヷ',
  13273. 'ヸ' => 'ヸ',
  13274. 'ヹ' => 'ヹ',
  13275. 'ヺ' => 'ヺ',
  13276. 'ヾ' => 'ヾ',
  13277. '豈' => '豈',
  13278. '�' => '更',
  13279. '車' => '車',
  13280. '賈' => '賈',
  13281. '滑' => '滑',
  13282. '串' => '串',
  13283. '句' => '�',
  13284. '龜' => '龜',
  13285. '龜' => '龜',
  13286. '契' => '契',
  13287. '金' => '金',
  13288. '喇' => '喇',
  13289. '奈' => '奈',
  13290. '�' => '懶',
  13291. '癩' => '癩',
  13292. '�' => '羅',
  13293. '�' => '蘿',
  13294. '螺' => '螺',
  13295. '裸' => '裸',
  13296. '邏' => '�',
  13297. '樂' => '樂',
  13298. '洛' => '洛',
  13299. '烙' => '烙',
  13300. '珞' => '�',
  13301. '落' => '�',
  13302. '酪' => '酪',
  13303. '駱' => '駱',
  13304. '亂' => '亂',
  13305. '卵' => '�',
  13306. '�' => '欄',
  13307. '爛' => '爛',
  13308. '蘭' => '蘭',
  13309. '鸞' => '鸞',
  13310. '嵐' => '�',
  13311. '濫' => '濫',
  13312. '藍' => '�',
  13313. '襤' => '襤',
  13314. '拉' => '拉',
  13315. '臘' => '臘',
  13316. '蠟' => '蠟',
  13317. '廊' => '廊',
  13318. '朗' => '朗',
  13319. '浪' => '浪',
  13320. '狼' => '狼',
  13321. '郎' => '郎',
  13322. '來' => '來',
  13323. '冷' => '冷',
  13324. '勞' => '勞',
  13325. '擄' => '擄',
  13326. '櫓' => '櫓',
  13327. '爐' => '�',
  13328. '盧' => '盧',
  13329. '老' => '�',
  13330. '蘆' => '蘆',
  13331. '虜' => '虜',
  13332. '路' => '路',
  13333. '露' => '露',
  13334. '魯' => '魯',
  13335. '鷺' => '鷺',
  13336. '碌' => '碌',
  13337. '祿' => '祿',
  13338. '綠' => '綠',
  13339. '菉' => '�',
  13340. '錄' => '錄',
  13341. '鹿' => '鹿',
  13342. '�' => '論',
  13343. '壟' => '壟',
  13344. '弄' => '弄',
  13345. '籠' => '籠',
  13346. '聾' => '�',
  13347. '牢' => '牢',
  13348. '磊' => '磊',
  13349. '賂' => '賂',
  13350. '雷' => '雷',
  13351. '壘' => '壘',
  13352. '屢' => '屢',
  13353. '樓' => '樓',
  13354. '�' => '淚',
  13355. '漏' => '�',
  13356. '�' => '累',
  13357. '�' => '縷',
  13358. '陋' => '陋',
  13359. '勒' => '勒',
  13360. '肋' => '肋',
  13361. '凜' => '凜',
  13362. '凌' => '凌',
  13363. '稜' => '稜',
  13364. '綾' => '綾',
  13365. '菱' => '�',
  13366. '陵' => '陵',
  13367. '讀' => '讀',
  13368. '拏' => '�',
  13369. '樂' => '樂',
  13370. '�' => '諾',
  13371. '丹' => '丹',
  13372. '寧' => '寧',
  13373. '怒' => '怒',
  13374. '率' => '率',
  13375. '異' => '異',
  13376. '北' => '北',
  13377. '磻' => '磻',
  13378. '便' => '便',
  13379. '復' => '復',
  13380. '不' => '�',
  13381. '泌' => '泌',
  13382. '數' => '數',
  13383. '索' => '索',
  13384. '參' => '�',
  13385. '塞' => '塞',
  13386. '省' => '�',
  13387. '葉' => '葉',
  13388. '說' => '說',
  13389. '殺' => '殺',
  13390. '辰' => '辰',
  13391. '沈' => '沈',
  13392. '拾' => '拾',
  13393. '若' => '若',
  13394. '掠' => '掠',
  13395. '略' => '略',
  13396. '亮' => '亮',
  13397. '兩' => '兩',
  13398. '凉' => '凉',
  13399. '梁' => '�',
  13400. '糧' => '糧',
  13401. '良' => '良',
  13402. '諒' => '諒',
  13403. '量' => '�',
  13404. '勵' => '勵',
  13405. '呂' => '呂',
  13406. '�' => '女',
  13407. '廬' => '廬',
  13408. '旅' => '旅',
  13409. '濾' => '濾',
  13410. '礪' => '礪',
  13411. '閭' => '閭',
  13412. '驪' => '驪',
  13413. '麗' => '麗',
  13414. '黎' => '黎',
  13415. '力' => '力',
  13416. '曆' => '曆',
  13417. '歷' => '歷',
  13418. '�' => '轢',
  13419. '年' => '年',
  13420. '�' => '�',
  13421. '�' => '戀',
  13422. '撚' => '撚',
  13423. '漣' => '漣',
  13424. '煉' => '煉',
  13425. '璉' => '璉',
  13426. '秊' => '秊',
  13427. '練' => '練',
  13428. '聯' => '�',
  13429. '輦' => '輦',
  13430. '蓮' => '蓮',
  13431. '連' => '連',
  13432. '鍊' => '�',
  13433. '列' => '列',
  13434. '�' => '劣',
  13435. '咽' => '咽',
  13436. '烈' => '烈',
  13437. '裂' => '裂',
  13438. '說' => '說',
  13439. '廉' => '廉',
  13440. '念' => '念',
  13441. '捻' => '�',
  13442. '殮' => '殮',
  13443. '簾' => '簾',
  13444. '獵' => '�',
  13445. '令' => '令',
  13446. '囹' => '囹',
  13447. '寧' => '寧',
  13448. '嶺' => '嶺',
  13449. '怜' => '怜',
  13450. '玲' => '玲',
  13451. '瑩' => '瑩',
  13452. '羚' => '羚',
  13453. '聆' => '�',
  13454. '鈴' => '鈴',
  13455. '零' => '零',
  13456. '靈' => '�',
  13457. '領' => '領',
  13458. '例' => '例',
  13459. '禮' => '禮',
  13460. '醴' => '醴',
  13461. '隸' => '隸',
  13462. '惡' => '惡',
  13463. '了' => '了',
  13464. '僚' => '僚',
  13465. '寮' => '寮',
  13466. '尿' => '尿',
  13467. '料' => '料',
  13468. '樂' => '樂',
  13469. '燎' => '燎',
  13470. '�' => '療',
  13471. '蓼' => '蓼',
  13472. '遼' => '�',
  13473. '龍' => '�',
  13474. '暈' => '暈',
  13475. '阮' => '阮',
  13476. '劉' => '劉',
  13477. '杻' => '�',
  13478. '柳' => '柳',
  13479. '流' => '�',
  13480. '溜' => '溜',
  13481. '琉' => '�',
  13482. '�' => '留',
  13483. 'ï§Ž' => 'ç¡«',
  13484. '�' => '�',
  13485. '�' => '類',
  13486. 'ï§‘' => 'å…­',
  13487. '戮' => '戮',
  13488. '陸' => '陸',
  13489. '倫' => '倫',
  13490. 'ï§•' => 'å´™',
  13491. 'ï§–' => 'æ·ª',
  13492. '輪' => '輪',
  13493. '律' => '律',
  13494. 'ï§™' => 'æ…„',
  13495. 'ï§š' => 'æ —',
  13496. '率' => '率',
  13497. '隆' => '隆',
  13498. '�' => '利',
  13499. '吏' => '�',
  13500. 'ï§Ÿ' => 'å±¥',
  13501. '易' => '易',
  13502. '李' => '�',
  13503. '梨' => '梨',
  13504. 'ï§£' => 'æ³¥',
  13505. '理' => '�',
  13506. 'ï§¥' => 'ç—¢',
  13507. '罹' => '罹',
  13508. '裏' => '�',
  13509. '裡' => '裡',
  13510. '里' => '里',
  13511. '離' => '離',
  13512. '匿' => '匿',
  13513. '溺' => '溺',
  13514. '吝' => '�',
  13515. '燐' => '�',
  13516. '璘' => '璘',
  13517. 'ï§°' => 'è—º',
  13518. '隣' => '隣',
  13519. 'ï§²' => 'é±—',
  13520. '麟' => '麟',
  13521. 'ï§´' => 'æž—',
  13522. 'ï§µ' => 'æ·‹',
  13523. '臨' => '臨',
  13524. 'ï§·' => 'ç«‹',
  13525. '笠' => '笠',
  13526. 'ï§¹' => 'ç²’',
  13527. '狀' => '狀',
  13528. 'ï§»' => 'ç‚™',
  13529. 'ï§¼' => 'è­˜',
  13530. '什' => '什',
  13531. '茶' => '茶',
  13532. '刺' => '刺',
  13533. '切' => '切',
  13534. '�' => '度',
  13535. '拓' => '拓',
  13536. '糖' => '糖',
  13537. '宅' => '宅',
  13538. '洞' => '洞',
  13539. '暴' => '暴',
  13540. '輻' => '輻',
  13541. '行' => '行',
  13542. '降' => '�',
  13543. '見' => '見',
  13544. '廓' => '廓',
  13545. '兀' => '兀',
  13546. '�' => '嗀',
  13547. '�' => '塚',
  13548. '晴' => '晴',
  13549. '凞' => '凞',
  13550. '猪' => '猪',
  13551. '益' => '益',
  13552. '礼' => '礼',
  13553. '神' => '神',
  13554. '祥' => '祥',
  13555. '福' => '�',
  13556. '靖' => '�',
  13557. '�' => '精',
  13558. '羽' => '羽',
  13559. '蘒' => '蘒',
  13560. '諸' => '諸',
  13561. '逸' => '逸',
  13562. '都' => '都',
  13563. '飯' => '飯',
  13564. '飼' => '飼',
  13565. '館' => '館',
  13566. '鶴' => '鶴',
  13567. '郞' => '郞',
  13568. '隷' => '隷',
  13569. '侮' => '侮',
  13570. '僧' => '僧',
  13571. '免' => '�',
  13572. '勉' => '勉',
  13573. '勤' => '勤',
  13574. '卑' => '�',
  13575. '喝' => '�',
  13576. '嘆' => '嘆',
  13577. '器' => '器',
  13578. '塀' => '塀',
  13579. '墨' => '墨',
  13580. '層' => '層',
  13581. '屮' => '屮',
  13582. '悔' => '悔',
  13583. '慨' => '慨',
  13584. '憎' => '憎',
  13585. '懲' => '懲',
  13586. '�' => '�',
  13587. 'ï©‚' => 'æ—¢',
  13588. '暑' => '暑',
  13589. '梅' => '梅',
  13590. 'ï©…' => 'æµ·',
  13591. '渚' => '渚',
  13592. '漢' => '漢',
  13593. '煮' => '煮',
  13594. '爫' => '爫',
  13595. '琢' => '�',
  13596. '碑' => '碑',
  13597. '社' => '社',
  13598. '�' => '祉',
  13599. '祈' => '祈',
  13600. '�' => '�',
  13601. '�' => '祖',
  13602. '祝' => '�',
  13603. '禍' => '�',
  13604. '禎' => '禎',
  13605. 'ï©”' => 'ç©€',
  13606. '突' => '�',
  13607. '節' => '節',
  13608. 'ï©—' => 'ç·´',
  13609. '縉' => '縉',
  13610. '繁' => '�',
  13611. '署' => '署',
  13612. '者' => '者',
  13613. '臭' => '臭',
  13614. '�' => '艹',
  13615. '艹' => '艹',
  13616. '著' => '著',
  13617. '褐' => '�',
  13618. '視' => '視',
  13619. '謁' => '�',
  13620. '謹' => '謹',
  13621. '賓' => '賓',
  13622. 'ï©¥' => 'è´ˆ',
  13623. '辶' => '辶',
  13624. '逸' => '逸',
  13625. '難' => '難',
  13626. '響' => '響',
  13627. '頻' => '頻',
  13628. '恵' => '�',
  13629. '𤋮' => '𤋮',
  13630. '舘' => '舘',
  13631. '並' => '並',
  13632. '况' => '况',
  13633. '全' => '全',
  13634. '侀' => '侀',
  13635. 'ï©´' => 'å……',
  13636. '冀' => '冀',
  13637. '勇' => '勇',
  13638. '勺' => '勺',
  13639. '喝' => '�',
  13640. '啕' => '啕',
  13641. '喙' => '喙',
  13642. 'ï©»' => 'å—¢',
  13643. '塚' => '塚',
  13644. '墳' => '墳',
  13645. '奄' => '奄',
  13646. '奔' => '奔',
  13647. '婢' => '婢',
  13648. '�' => '嬨',
  13649. '廒' => '廒',
  13650. '廙' => '廙',
  13651. '彩' => '彩',
  13652. '徭' => '徭',
  13653. '惘' => '惘',
  13654. '慎' => '慎',
  13655. '愈' => '愈',
  13656. '憎' => '憎',
  13657. '慠' => '慠',
  13658. '懲' => '懲',
  13659. '戴' => '戴',
  13660. '�' => '�',
  13661. '搜' => '�',
  13662. '�' => '摒',
  13663. '�' => '敖',
  13664. '晴' => '晴',
  13665. '朗' => '朗',
  13666. '望' => '望',
  13667. '杖' => '�',
  13668. '歹' => '歹',
  13669. '殺' => '殺',
  13670. '流' => '�',
  13671. '滛' => '滛',
  13672. '滋' => '滋',
  13673. '漢' => '漢',
  13674. '瀞' => '瀞',
  13675. '煮' => '煮',
  13676. '�' => '瞧',
  13677. '爵' => '爵',
  13678. '犯' => '犯',
  13679. '猪' => '猪',
  13680. '瑱' => '瑱',
  13681. '甆' => '甆',
  13682. '画' => '画',
  13683. '瘝' => '�',
  13684. '瘟' => '瘟',
  13685. '益' => '益',
  13686. '盛' => '盛',
  13687. '直' => '直',
  13688. '睊' => '�',
  13689. '着' => '�',
  13690. '磌' => '磌',
  13691. '窱' => '窱',
  13692. '節' => '節',
  13693. '类' => '类',
  13694. '絛' => '絛',
  13695. '練' => '練',
  13696. '缾' => '缾',
  13697. '者' => '者',
  13698. '荒' => '�',
  13699. '華' => '�',
  13700. '蝹' => '�',
  13701. '襁' => '�',
  13702. '覆' => '覆',
  13703. '視' => '視',
  13704. '調' => '調',
  13705. '諸' => '諸',
  13706. '請' => '請',
  13707. '謁' => '�',
  13708. '諾' => '諾',
  13709. '諭' => '諭',
  13710. '謹' => '謹',
  13711. '變' => '變',
  13712. '�' => '贈',
  13713. '輸' => '輸',
  13714. '遲' => '�',
  13715. '醙' => '醙',
  13716. '鉶' => '鉶',
  13717. '陼' => '陼',
  13718. '難' => '難',
  13719. '靖' => '�',
  13720. '韛' => '韛',
  13721. '響' => '響',
  13722. 'ï«‹' => 'é ‹',
  13723. '頻' => '頻',
  13724. '�' => '鬒',
  13725. '龜' => '龜',
  13726. '�' => '𢡊',
  13727. '�' => '𢡄',
  13728. '𣏕' => '�',
  13729. '㮝' => '�',
  13730. '䀘' => '䀘',
  13731. '䀹' => '䀹',
  13732. '𥉉' => '𥉉',
  13733. '𥳐' => '�',
  13734. '𧻓' => '𧻓',
  13735. '齃' => '齃',
  13736. '龎' => '龎',
  13737. '�' => 'יִ',
  13738. 'ײַ' => 'ײַ',
  13739. 'שׁ' => 'ש�',
  13740. 'שׂ' => 'שׂ',
  13741. 'שּׁ' => 'שּ�',
  13742. 'שּׂ' => 'שּׂ',
  13743. 'אַ' => '�ַ',
  13744. 'אָ' => '�ָ',
  13745. 'אּ' => '�ּ',
  13746. 'בּ' => 'בּ',
  13747. 'גּ' => 'גּ',
  13748. 'דּ' => 'דּ',
  13749. 'הּ' => 'הּ',
  13750. 'וּ' => 'וּ',
  13751. 'זּ' => 'זּ',
  13752. 'טּ' => 'טּ',
  13753. 'יּ' => 'יּ',
  13754. 'ךּ' => 'ךּ',
  13755. 'כּ' => 'כּ',
  13756. 'לּ' => 'לּ',
  13757. 'מּ' => 'מּ',
  13758. 'ï­€' => '× Ö¼',
  13759. '�' => 'סּ',
  13760. 'ï­ƒ' => '×£Ö¼',
  13761. 'פּ' => 'פּ',
  13762. 'צּ' => 'צּ',
  13763. 'ï­‡' => '×§Ö¼',
  13764. 'רּ' => 'רּ',
  13765. 'שּ' => 'שּ',
  13766. 'תּ' => 'תּ',
  13767. 'וֹ' => 'וֹ',
  13768. 'בֿ' => 'בֿ',
  13769. 'ï­�' => '×›Ö¿',
  13770. 'פֿ' => 'פֿ',
  13771. '𑂚' => '𑂚',
  13772. '𑂜' => '𑂜',
  13773. '𑂫' => '𑂫',
  13774. '𑄮' => '𑄮',
  13775. '𑄯' => '𑄯',
  13776. '�' => '�𑌾',
  13777. '�' => '��',
  13778. '𑒻' => '𑒻',
  13779. '𑒼' => '𑒼',
  13780. '𑒾' => '𑒾',
  13781. '𑖺' => '𑖺',
  13782. '𑖻' => '𑖻',
  13783. '𑤸' => '𑤸',
  13784. '�' => '��',
  13785. '�' => '��',
  13786. '�' => '���',
  13787. '�' => '���',
  13788. '�' => '���',
  13789. '�' => '���',
  13790. '�' => '���',
  13791. '�' => '��',
  13792. '�' => '��',
  13793. '�' => '���',
  13794. '�' => '���',
  13795. '�' => '���',
  13796. '�' => '���',
  13797. '丽' => '丽',
  13798. '�' => '丸',
  13799. '乁' => '�',
  13800. '𠄢' => '𠄢',
  13801. '你' => '你',
  13802. '侮' => '侮',
  13803. '侻' => '侻',
  13804. '倂' => '倂',
  13805. '偺' => '�',
  13806. '備' => '備',
  13807. '僧' => '僧',
  13808. '像' => '�',
  13809. '㒞' => '㒞',
  13810. '�' => '𠘺',
  13811. '免' => '�',
  13812. '�' => '兔',
  13813. '�' => '兤',
  13814. '具' => '具',
  13815. '𠔜' => '𠔜',
  13816. '㒹' => '㒹',
  13817. '內' => '內',
  13818. '再' => '�',
  13819. '𠕋' => '𠕋',
  13820. '冗' => '冗',
  13821. '冤' => '冤',
  13822. '仌' => '仌',
  13823. '冬' => '冬',
  13824. '况' => '况',
  13825. '𩇟' => '𩇟',
  13826. '�' => '凵',
  13827. '刃' => '刃',
  13828. '㓟' => '㓟',
  13829. '刻' => '刻',
  13830. '剆' => '剆',
  13831. '割' => '割',
  13832. '剷' => '剷',
  13833. '㔕' => '㔕',
  13834. '勇' => '勇',
  13835. '勉' => '勉',
  13836. '勤' => '勤',
  13837. '勺' => '勺',
  13838. '包' => '包',
  13839. '匆' => '匆',
  13840. '北' => '北',
  13841. '卉' => '�',
  13842. '卑' => '�',
  13843. '博' => '�',
  13844. '即' => '�',
  13845. '卽' => '�',
  13846. '卿' => '�',
  13847. '卿' => '�',
  13848. '卿' => '�',
  13849. '𠨬' => '𠨬',
  13850. '灰' => '�',
  13851. '及' => '�',
  13852. '叟' => '�',
  13853. '𠭣' => '𠭣',
  13854. '叫' => '�',
  13855. '叱' => '�',
  13856. '吆' => '�',
  13857. '咞' => '咞',
  13858. '吸' => '�',
  13859. '呈' => '呈',
  13860. '周' => '周',
  13861. '咢' => '咢',
  13862. '�' => '哶',
  13863. '唐' => '�',
  13864. '啓' => '啓',
  13865. '啣' => '啣',
  13866. '善' => '善',
  13867. '善' => '善',
  13868. '喙' => '喙',
  13869. '喫' => '喫',
  13870. '喳' => '喳',
  13871. '嗂' => '嗂',
  13872. '圖' => '圖',
  13873. '嘆' => '嘆',
  13874. '�' => '圗',
  13875. '噑' => '噑',
  13876. '�' => '噴',
  13877. '�' => '切',
  13878. '壮' => '壮',
  13879. '城' => '城',
  13880. '埴' => '埴',
  13881. '堍' => '�',
  13882. '型' => '型',
  13883. '堲' => '堲',
  13884. '報' => '報',
  13885. '墬' => '墬',
  13886. '𡓤' => '𡓤',
  13887. '売' => '売',
  13888. '壷' => '壷',
  13889. '夆' => '夆',
  13890. '�' => '多',
  13891. '夢' => '夢',
  13892. '奢' => '奢',
  13893. '𡚨' => '𡚨',
  13894. '𡛪' => '𡛪',
  13895. '姬' => '姬',
  13896. '娛' => '娛',
  13897. '娧' => '娧',
  13898. '姘' => '姘',
  13899. '婦' => '婦',
  13900. '㛮' => '㛮',
  13901. '㛼' => '㛼',
  13902. '嬈' => '嬈',
  13903. '嬾' => '嬾',
  13904. '嬾' => '嬾',
  13905. '𡧈' => '𡧈',
  13906. '寃' => '寃',
  13907. '寘' => '寘',
  13908. '寧' => '寧',
  13909. '寳' => '寳',
  13910. '𡬘' => '𡬘',
  13911. '寿' => '寿',
  13912. '将' => '将',
  13913. '当' => '当',
  13914. '尢' => '尢',
  13915. '㞁' => '�',
  13916. '屠' => '屠',
  13917. '屮' => '屮',
  13918. '峀' => '峀',
  13919. '岍' => '�',
  13920. '𡷤' => '𡷤',
  13921. '嵃' => '嵃',
  13922. '𡷦' => '𡷦',
  13923. '嵮' => '嵮',
  13924. '嵫' => '嵫',
  13925. '嵼' => '嵼',
  13926. '�' => '巡',
  13927. '巢' => '巢',
  13928. '㠯' => '㠯',
  13929. '巽' => '巽',
  13930. '帨' => '帨',
  13931. '帽' => '帽',
  13932. '幩' => '幩',
  13933. '㡢' => '㡢',
  13934. '𢆃' => '𢆃',
  13935. '㡼' => '㡼',
  13936. '庰' => '庰',
  13937. '庳' => '庳',
  13938. '�' => '庶',
  13939. '廊' => '廊',
  13940. '�' => '𪎒',
  13941. '�' => '廾',
  13942. '𢌱' => '𢌱',
  13943. '𢌱' => '𢌱',
  13944. '舁' => '�',
  13945. '弢' => '弢',
  13946. '弢' => '弢',
  13947. '㣇' => '㣇',
  13948. '𣊸' => '𣊸',
  13949. '𦇚' => '𦇚',
  13950. '形' => '形',
  13951. '彫' => '彫',
  13952. '㣣' => '㣣',
  13953. '徚' => '徚',
  13954. '�' => '�',
  13955. '志' => '志',
  13956. '忹' => '忹',
  13957. '悁' => '�',
  13958. '㤺' => '㤺',
  13959. '㤜' => '㤜',
  13960. '悔' => '悔',
  13961. '𢛔' => '𢛔',
  13962. '惇' => '惇',
  13963. '慈' => '慈',
  13964. '慌' => '慌',
  13965. '慎' => '慎',
  13966. '慌' => '慌',
  13967. '慺' => '慺',
  13968. '憎' => '憎',
  13969. '憲' => '憲',
  13970. '憤' => '憤',
  13971. '憯' => '憯',
  13972. '懞' => '懞',
  13973. '懲' => '懲',
  13974. '懶' => '懶',
  13975. '成' => '�',
  13976. '戛' => '戛',
  13977. '扝' => '�',
  13978. '抱' => '抱',
  13979. '拔' => '拔',
  13980. '捐' => '�',
  13981. '𢬌' => '𢬌',
  13982. '挽' => '挽',
  13983. '拼' => '拼',
  13984. '捨' => '�',
  13985. '掃' => '掃',
  13986. '揤' => '�',
  13987. '𢯱' => '𢯱',
  13988. '搢' => '�',
  13989. '揅' => '�',
  13990. '�' => '掩',
  13991. '㨮' => '㨮',
  13992. '摩' => '摩',
  13993. '摾' => '摾',
  13994. '撝' => '�',
  13995. '摷' => '摷',
  13996. '㩬' => '㩬',
  13997. '敏' => '�',
  13998. '敬' => '敬',
  13999. '𣀊' => '𣀊',
  14000. '旣' => '旣',
  14001. '書' => '書',
  14002. '�' => '晉',
  14003. '㬙' => '㬙',
  14004. '�' => '暑',
  14005. '�' => '㬈',
  14006. '㫤' => '㫤',
  14007. '冒' => '冒',
  14008. '冕' => '冕',
  14009. '最' => '最',
  14010. '暜' => '暜',
  14011. '肭' => '肭',
  14012. '䏙' => '�',
  14013. '朗' => '朗',
  14014. '望' => '望',
  14015. '朡' => '朡',
  14016. '杞' => '�',
  14017. '杓' => '�',
  14018. '�' => '�',
  14019. '㭉' => '㭉',
  14020. '柺' => '柺',
  14021. '枅' => '枅',
  14022. '桒' => '桒',
  14023. '梅' => '梅',
  14024. '𣑭' => '𣑭',
  14025. '梎' => '梎',
  14026. '栟' => '栟',
  14027. '椔' => '椔',
  14028. '㮝' => '�',
  14029. '楂' => '楂',
  14030. '榣' => '榣',
  14031. '槪' => '槪',
  14032. '檨' => '檨',
  14033. '𣚣' => '𣚣',
  14034. '櫛' => '櫛',
  14035. '㰘' => '㰘',
  14036. '次' => '次',
  14037. '𣢧' => '𣢧',
  14038. '歔' => '歔',
  14039. '㱎' => '㱎',
  14040. '歲' => '歲',
  14041. '殟' => '殟',
  14042. '殺' => '殺',
  14043. '殻' => '殻',
  14044. '𣪍' => '�',
  14045. '𡴋' => '𡴋',
  14046. '𣫺' => '𣫺',
  14047. '汎' => '汎',
  14048. '𣲼' => '𣲼',
  14049. '沿' => '沿',
  14050. '泍' => '�',
  14051. '汧' => '汧',
  14052. '洖' => '洖',
  14053. '派' => '派',
  14054. '�' => '海',
  14055. '流' => '�',
  14056. '浩' => '浩',
  14057. '浸' => '浸',
  14058. '涅' => '涅',
  14059. '𣴞' => '𣴞',
  14060. '洴' => '洴',
  14061. '港' => '港',
  14062. '湮' => '湮',
  14063. '㴳' => '㴳',
  14064. '滋' => '滋',
  14065. '滇' => '滇',
  14066. '�' => '𣻑',
  14067. '淹' => '淹',
  14068. '�' => '潮',
  14069. '�' => '𣽞',
  14070. '𣾎' => '𣾎',
  14071. '濆' => '濆',
  14072. '瀹' => '瀹',
  14073. '瀞' => '瀞',
  14074. '瀛' => '瀛',
  14075. '㶖' => '㶖',
  14076. '灊' => '�',
  14077. '災' => '�',
  14078. '灷' => '�',
  14079. '炭' => '炭',
  14080. '𠔥' => '𠔥',
  14081. '煅' => '煅',
  14082. '�' => '𤉣',
  14083. '熜' => '熜',
  14084. '𤎫' => '𤎫',
  14085. '爨' => '爨',
  14086. '爵' => '爵',
  14087. '牐' => '�',
  14088. '𤘈' => '𤘈',
  14089. '犀' => '犀',
  14090. '犕' => '犕',
  14091. '𤜵' => '𤜵',
  14092. '𤠔' => '𤠔',
  14093. '獺' => '�',
  14094. '王' => '王',
  14095. '㺬' => '㺬',
  14096. '玥' => '玥',
  14097. '㺸' => '㺸',
  14098. '㺸' => '㺸',
  14099. '瑇' => '瑇',
  14100. '瑜' => '瑜',
  14101. '瑱' => '瑱',
  14102. '璅' => '璅',
  14103. '瓊' => '瓊',
  14104. '㼛' => '㼛',
  14105. '甤' => '甤',
  14106. '𤰶' => '𤰶',
  14107. '甾' => '甾',
  14108. '𤲒' => '𤲒',
  14109. '異' => '異',
  14110. '𢆟' => '𢆟',
  14111. '瘐' => '�',
  14112. '𤾡' => '𤾡',
  14113. '𤾸' => '𤾸',
  14114. '𥁄' => '�',
  14115. '㿼' => '㿼',
  14116. '䀈' => '䀈',
  14117. '直' => '直',
  14118. '�' => '𥃳',
  14119. '𥃲' => '𥃲',
  14120. '𥄙' => '𥄙',
  14121. '𥄳' => '𥄳',
  14122. '眞' => '眞',
  14123. '真' => '真',
  14124. '真' => '真',
  14125. '睊' => '�',
  14126. '䀹' => '䀹',
  14127. '瞋' => '瞋',
  14128. '䁆' => '�',
  14129. '䂖' => '䂖',
  14130. '�' => '�',
  14131. '硎' => '硎',
  14132. '�' => '碌',
  14133. '�' => '磌',
  14134. '䃣' => '䃣',
  14135. '𥘦' => '𥘦',
  14136. '祖' => '祖',
  14137. '𥚚' => '𥚚',
  14138. '𥛅' => '𥛅',
  14139. '福' => '�',
  14140. '秫' => '秫',
  14141. '䄯' => '䄯',
  14142. '穀' => '穀',
  14143. '穊' => '穊',
  14144. '穏' => '�',
  14145. '𥥼' => '𥥼',
  14146. '�' => '𥪧',
  14147. '𥪧' => '𥪧',
  14148. '竮' => '竮',
  14149. '䈂' => '䈂',
  14150. '𥮫' => '𥮫',
  14151. '篆' => '篆',
  14152. '築' => '築',
  14153. '䈧' => '䈧',
  14154. '𥲀' => '𥲀',
  14155. '糒' => '糒',
  14156. '䊠' => '䊠',
  14157. '糨' => '糨',
  14158. '糣' => '糣',
  14159. '紀' => '紀',
  14160. '𥾆' => '𥾆',
  14161. '絣' => '絣',
  14162. '䌁' => '�',
  14163. '緇' => '緇',
  14164. '縂' => '縂',
  14165. '繅' => '繅',
  14166. '䌴' => '䌴',
  14167. '𦈨' => '𦈨',
  14168. '𦉇' => '𦉇',
  14169. '䍙' => '�',
  14170. '𦋙' => '𦋙',
  14171. '罺' => '罺',
  14172. '𦌾' => '𦌾',
  14173. '羕' => '羕',
  14174. '翺' => '翺',
  14175. '者' => '者',
  14176. '𦓚' => '𦓚',
  14177. '𦔣' => '𦔣',
  14178. '聠' => '�',
  14179. '𦖨' => '𦖨',
  14180. '聰' => '�',
  14181. '𣍟' => '�',
  14182. '�' => '�',
  14183. '育' => '育',
  14184. '脃' => '脃',
  14185. '䐋' => '�',
  14186. '脾' => '脾',
  14187. '媵' => '媵',
  14188. '𦞧' => '𦞧',
  14189. '𦞵' => '𦞵',
  14190. '𣎓' => '𣎓',
  14191. '𣎜' => '𣎜',
  14192. '舁' => '�',
  14193. '舄' => '舄',
  14194. '�' => '辞',
  14195. '䑫' => '䑫',
  14196. '�' => '芑',
  14197. '�' => '芋',
  14198. '芝' => '�',
  14199. '劳' => '劳',
  14200. '花' => '花',
  14201. '芳' => '芳',
  14202. '芽' => '芽',
  14203. '苦' => '苦',
  14204. '𦬼' => '𦬼',
  14205. '若' => '若',
  14206. '茝' => '�',
  14207. '荣' => '�',
  14208. '莭' => '莭',
  14209. '茣' => '茣',
  14210. '�' => '莽',
  14211. '菧' => '�',
  14212. '著' => '著',
  14213. '荓' => '�',
  14214. '菊' => '�',
  14215. '菌' => '�',
  14216. '菜' => '�',
  14217. '𦰶' => '𦰶',
  14218. '𦵫' => '𦵫',
  14219. '𦳕' => '𦳕',
  14220. '䔫' => '䔫',
  14221. '蓱' => '蓱',
  14222. '蓳' => '蓳',
  14223. '蔖' => '蔖',
  14224. '𧏊' => '�',
  14225. '蕤' => '蕤',
  14226. '𦼬' => '𦼬',
  14227. '䕝' => '�',
  14228. '䕡' => '䕡',
  14229. '𦾱' => '𦾱',
  14230. '𧃒' => '𧃒',
  14231. '䕫' => '䕫',
  14232. '虐' => '�',
  14233. '虜' => '虜',
  14234. '虧' => '虧',
  14235. '虩' => '虩',
  14236. '蚩' => '蚩',
  14237. '蚈' => '蚈',
  14238. '蜎' => '蜎',
  14239. '蛢' => '蛢',
  14240. '蝹' => '�',
  14241. '蜨' => '蜨',
  14242. '蝫' => '�',
  14243. '螆' => '螆',
  14244. '䗗' => '䗗',
  14245. '蟡' => '蟡',
  14246. '�' => '�',
  14247. '䗹' => '䗹',
  14248. '衠' => '衠',
  14249. '衣' => '衣',
  14250. '𧙧' => '𧙧',
  14251. '裗' => '裗',
  14252. '裞' => '裞',
  14253. '䘵' => '䘵',
  14254. '裺' => '裺',
  14255. '㒻' => '㒻',
  14256. '𧢮' => '𧢮',
  14257. '𧥦' => '𧥦',
  14258. '�' => '䚾',
  14259. '䛇' => '䛇',
  14260. '�' => '誠',
  14261. '�' => '諭',
  14262. '變' => '變',
  14263. '豕' => '豕',
  14264. '𧲨' => '𧲨',
  14265. '貫' => '貫',
  14266. '賁' => '�',
  14267. '贛' => '贛',
  14268. '起' => '起',
  14269. '𧼯' => '𧼯',
  14270. '𠠄' => '𠠄',
  14271. '跋' => '跋',
  14272. '趼' => '趼',
  14273. '跰' => '跰',
  14274. '�' => '𠣞',
  14275. '軔' => '軔',
  14276. '輸' => '輸',
  14277. '𨗒' => '𨗒',
  14278. '𨗭' => '𨗭',
  14279. '邔' => '邔',
  14280. '郱' => '郱',
  14281. '鄑' => '鄑',
  14282. '𨜮' => '𨜮',
  14283. '鄛' => '鄛',
  14284. '鈸' => '鈸',
  14285. '鋗' => '鋗',
  14286. '鋘' => '鋘',
  14287. '鉼' => '鉼',
  14288. '鏹' => '�',
  14289. '鐕' => '�',
  14290. '𨯺' => '𨯺',
  14291. '開' => '開',
  14292. '䦕' => '䦕',
  14293. '閷' => '閷',
  14294. '𨵷' => '𨵷',
  14295. '䧦' => '䧦',
  14296. '雃' => '雃',
  14297. '嶲' => '嶲',
  14298. '霣' => '霣',
  14299. '𩅅' => '𩅅',
  14300. '𩈚' => '𩈚',
  14301. '䩮' => '䩮',
  14302. '䩶' => '䩶',
  14303. '韠' => '韠',
  14304. '𩐊' => '�',
  14305. '䪲' => '䪲',
  14306. '𩒖' => '𩒖',
  14307. '頋' => '頋',
  14308. '頋' => '頋',
  14309. '頩' => '頩',
  14310. '�' => '𩖶',
  14311. '飢' => '飢',
  14312. '䬳' => '䬳',
  14313. '餩' => '餩',
  14314. '馧' => '馧',
  14315. '駂' => '駂',
  14316. '駾' => '駾',
  14317. '䯎' => '䯎',
  14318. '𩬰' => '𩬰',
  14319. '鬒' => '鬒',
  14320. '鱀' => '鱀',
  14321. '鳽' => '鳽',
  14322. '�' => '䳎',
  14323. '䳭' => '䳭',
  14324. '�' => '鵧',
  14325. '�' => '𪃎',
  14326. '䳸' => '䳸',
  14327. '𪄅' => '𪄅',
  14328. '𪈎' => '𪈎',
  14329. '𪊑' => '𪊑',
  14330. '麻' => '麻',
  14331. '䵖' => '䵖',
  14332. '黹' => '黹',
  14333. '黾' => '黾',
  14334. '鼅' => '鼅',
  14335. '鼏' => '�',
  14336. '鼖' => '鼖',
  14337. '鼻' => '鼻',
  14338. '�' => '𪘀',
  14339. );
  14340. <?php
  14341. return array (
  14342. 'À' => 'À',
  14343. 'A�' => '�',
  14344. 'Â' => 'Â',
  14345. 'Ã' => 'Ã',
  14346. 'Ä' => 'Ä',
  14347. 'AÌŠ' => 'Ã…',
  14348. 'Ç' => 'Ç',
  14349. 'È' => 'È',
  14350. 'E�' => 'É',
  14351. 'Ê' => 'Ê',
  14352. 'Ë' => 'Ë',
  14353. 'Ì' => 'Ì',
  14354. 'I�' => '�',
  14355. 'IÌ‚' => 'ÃŽ',
  14356. 'Ï' => '�',
  14357. 'Ñ' => 'Ñ',
  14358. 'OÌ€' => 'Ã’',
  14359. 'O�' => 'Ó',
  14360. 'Ô' => 'Ô',
  14361. 'Õ' => 'Õ',
  14362. 'Ö' => 'Ö',
  14363. 'Ù' => 'Ù',
  14364. 'U�' => 'Ú',
  14365. 'Û' => 'Û',
  14366. 'Ü' => 'Ü',
  14367. 'Y�' => '�',
  14368. 'à' => 'à',
  14369. 'a�' => 'á',
  14370. 'â' => 'â',
  14371. 'ã' => 'ã',
  14372. 'ä' => 'ä',
  14373. 'aÌŠ' => 'Ã¥',
  14374. 'ç' => 'ç',
  14375. 'è' => 'è',
  14376. 'e�' => 'é',
  14377. 'ê' => 'ê',
  14378. 'ë' => 'ë',
  14379. 'ì' => 'ì',
  14380. 'i�' => 'í',
  14381. 'î' => 'î',
  14382. 'ï' => 'ï',
  14383. 'ñ' => 'ñ',
  14384. 'ò' => 'ò',
  14385. 'o�' => 'ó',
  14386. 'ô' => 'ô',
  14387. 'õ' => 'õ',
  14388. 'ö' => 'ö',
  14389. 'ù' => 'ù',
  14390. 'u�' => 'ú',
  14391. 'û' => 'û',
  14392. 'ü' => 'ü',
  14393. 'y�' => 'ý',
  14394. 'ÿ' => 'ÿ',
  14395. 'AÌ„' => 'Ä€',
  14396. 'ā' => '�',
  14397. 'Ă' => 'Ă',
  14398. 'ă' => 'ă',
  14399. 'Ą' => 'Ą',
  14400. 'ą' => 'ą',
  14401. 'C�' => 'Ć',
  14402. 'c�' => 'ć',
  14403. 'Ĉ' => 'Ĉ',
  14404. 'ĉ' => 'ĉ',
  14405. 'Ċ' => 'Ċ',
  14406. 'ċ' => 'ċ',
  14407. 'Č' => 'Č',
  14408. 'č' => '�',
  14409. 'Ď' => 'Ď',
  14410. 'ď' => '�',
  14411. 'EÌ„' => 'Ä’',
  14412. 'ē' => 'ē',
  14413. 'Ĕ' => 'Ĕ',
  14414. 'ĕ' => 'ĕ',
  14415. 'Ė' => 'Ė',
  14416. 'ė' => 'ė',
  14417. 'Ę' => 'Ę',
  14418. 'ę' => 'ę',
  14419. 'Ě' => 'Ě',
  14420. 'ě' => 'ě',
  14421. 'Ĝ' => 'Ĝ',
  14422. 'ĝ' => '�',
  14423. 'Ğ' => 'Ğ',
  14424. 'ğ' => 'ğ',
  14425. 'Ġ' => 'Ġ',
  14426. 'ġ' => 'ġ',
  14427. 'Ģ' => 'Ģ',
  14428. 'ģ' => 'ģ',
  14429. 'Ĥ' => 'Ĥ',
  14430. 'ĥ' => 'ĥ',
  14431. 'Ĩ' => 'Ĩ',
  14432. 'ĩ' => 'ĩ',
  14433. 'Ī' => 'Ī',
  14434. 'ī' => 'ī',
  14435. 'Ĭ' => 'Ĭ',
  14436. 'ĭ' => 'ĭ',
  14437. 'Į' => 'Į',
  14438. 'į' => 'į',
  14439. 'İ' => 'İ',
  14440. 'JÌ‚' => 'Ä´',
  14441. 'ĵ' => 'ĵ',
  14442. 'Ķ' => 'Ķ',
  14443. 'ķ' => 'ķ',
  14444. 'L�' => 'Ĺ',
  14445. 'l�' => 'ĺ',
  14446. 'Ļ' => 'Ļ',
  14447. 'ļ' => 'ļ',
  14448. 'Ľ' => 'Ľ',
  14449. 'ľ' => 'ľ',
  14450. 'N�' => 'Ń',
  14451. 'n�' => 'ń',
  14452. 'Ņ' => 'Ņ',
  14453. 'ņ' => 'ņ',
  14454. 'Ň' => 'Ň',
  14455. 'ň' => 'ň',
  14456. 'Ō' => 'Ō',
  14457. 'ō' => '�',
  14458. 'Ŏ' => 'Ŏ',
  14459. 'ŏ' => '�',
  14460. 'Ő' => '�',
  14461. 'ő' => 'ő',
  14462. 'R�' => 'Ŕ',
  14463. 'r�' => 'ŕ',
  14464. 'Ŗ' => 'Ŗ',
  14465. 'ŗ' => 'ŗ',
  14466. 'Ř' => 'Ř',
  14467. 'ř' => 'ř',
  14468. 'S�' => 'Ś',
  14469. 's�' => 'ś',
  14470. 'Ŝ' => 'Ŝ',
  14471. 'ŝ' => '�',
  14472. 'Ş' => 'Ş',
  14473. 'ş' => 'ş',
  14474. 'Š' => 'Š',
  14475. 'š' => 'š',
  14476. 'Ţ' => 'Ţ',
  14477. 'ţ' => 'ţ',
  14478. 'Ť' => 'Ť',
  14479. 'ť' => 'ť',
  14480. 'Ũ' => 'Ũ',
  14481. 'ũ' => 'ũ',
  14482. 'Ū' => 'Ū',
  14483. 'ū' => 'ū',
  14484. 'Ŭ' => 'Ŭ',
  14485. 'ŭ' => 'ŭ',
  14486. 'UÌŠ' => 'Å®',
  14487. 'ů' => 'ů',
  14488. 'Ű' => 'Ű',
  14489. 'ű' => 'ű',
  14490. 'Ų' => 'Ų',
  14491. 'ų' => 'ų',
  14492. 'WÌ‚' => 'Å´',
  14493. 'ŵ' => 'ŵ',
  14494. 'Ŷ' => 'Ŷ',
  14495. 'ŷ' => 'ŷ',
  14496. 'Ÿ' => 'Ÿ',
  14497. 'Z�' => 'Ź',
  14498. 'z�' => 'ź',
  14499. 'Ż' => 'Ż',
  14500. 'ż' => 'ż',
  14501. 'Ž' => 'Ž',
  14502. 'ž' => 'ž',
  14503. 'OÌ›' => 'Æ ',
  14504. 'oÌ›' => 'Æ¡',
  14505. 'Ư' => 'Ư',
  14506. 'ư' => 'ư',
  14507. 'Ǎ' => '�',
  14508. 'ǎ' => 'ǎ',
  14509. 'Ǐ' => '�',
  14510. 'ǐ' => '�',
  14511. 'Ǒ' => 'Ǒ',
  14512. 'ǒ' => 'ǒ',
  14513. 'Ǔ' => 'Ǔ',
  14514. 'ǔ' => 'ǔ',
  14515. 'Ǖ' => 'Ǖ',
  14516. 'ǖ' => 'ǖ',
  14517. 'Ü�' => 'Ǘ',
  14518. 'ü�' => 'ǘ',
  14519. 'Ǚ' => 'Ǚ',
  14520. 'ǚ' => 'ǚ',
  14521. 'Ǜ' => 'Ǜ',
  14522. 'ǜ' => 'ǜ',
  14523. 'Ǟ' => 'Ǟ',
  14524. 'ǟ' => 'ǟ',
  14525. 'Ǡ' => 'Ǡ',
  14526. 'ǡ' => 'ǡ',
  14527. 'Ǣ' => 'Ǣ',
  14528. 'ǣ' => 'ǣ',
  14529. 'Ǧ' => 'Ǧ',
  14530. 'ǧ' => 'ǧ',
  14531. 'Ǩ' => 'Ǩ',
  14532. 'ǩ' => 'ǩ',
  14533. 'Ǫ' => 'Ǫ',
  14534. 'ǫ' => 'ǫ',
  14535. 'Ǭ' => 'Ǭ',
  14536. 'ǭ' => 'ǭ',
  14537. 'Ǯ' => 'Ǯ',
  14538. 'ǯ' => 'ǯ',
  14539. 'ǰ' => 'ǰ',
  14540. 'G�' => 'Ǵ',
  14541. 'g�' => 'ǵ',
  14542. 'Ǹ' => 'Ǹ',
  14543. 'ǹ' => 'ǹ',
  14544. 'Å�' => 'Ǻ',
  14545. 'å�' => 'ǻ',
  14546. 'Æ�' => 'Ǽ',
  14547. 'æ�' => 'ǽ',
  14548. 'Ø�' => 'Ǿ',
  14549. 'ø�' => 'ǿ',
  14550. 'A�' => 'Ȁ',
  14551. 'a�' => '�',
  14552. 'AÌ‘' => 'È‚',
  14553. 'ȃ' => 'ȃ',
  14554. 'E�' => 'Ȅ',
  14555. 'e�' => 'ȅ',
  14556. 'Ȇ' => 'Ȇ',
  14557. 'ȇ' => 'ȇ',
  14558. 'I�' => 'Ȉ',
  14559. 'i�' => 'ȉ',
  14560. 'IÌ‘' => 'ÈŠ',
  14561. 'ȋ' => 'ȋ',
  14562. 'O�' => 'Ȍ',
  14563. 'o�' => '�',
  14564. 'OÌ‘' => 'ÈŽ',
  14565. 'ȏ' => '�',
  14566. 'R�' => '�',
  14567. 'r�' => 'ȑ',
  14568. 'RÌ‘' => 'È’',
  14569. 'ȓ' => 'ȓ',
  14570. 'U�' => 'Ȕ',
  14571. 'u�' => 'ȕ',
  14572. 'UÌ‘' => 'È–',
  14573. 'ȗ' => 'ȗ',
  14574. 'Ș' => 'Ș',
  14575. 'ș' => 'ș',
  14576. 'Ț' => 'Ț',
  14577. 'ț' => 'ț',
  14578. 'Ȟ' => 'Ȟ',
  14579. 'ȟ' => 'ȟ',
  14580. 'Ȧ' => 'Ȧ',
  14581. 'ȧ' => 'ȧ',
  14582. 'Ȩ' => 'Ȩ',
  14583. 'ȩ' => 'ȩ',
  14584. 'Ȫ' => 'Ȫ',
  14585. 'ȫ' => 'ȫ',
  14586. 'Ȭ' => 'Ȭ',
  14587. 'ȭ' => 'ȭ',
  14588. 'Ȯ' => 'Ȯ',
  14589. 'ȯ' => 'ȯ',
  14590. 'Ȱ' => 'Ȱ',
  14591. 'ȱ' => 'ȱ',
  14592. 'Ȳ' => 'Ȳ',
  14593. 'ȳ' => 'ȳ',
  14594. '¨�' => '΅',
  14595. 'Α�' => 'Ά',
  14596. 'Ε�' => 'Έ',
  14597. 'Η�' => 'Ή',
  14598. 'Ι�' => 'Ί',
  14599. 'Ο�' => 'Ό',
  14600. 'Υ�' => 'Ύ',
  14601. 'Ω�' => '�',
  14602. 'ϊ�' => '�',
  14603. 'Ϊ' => 'Ϊ',
  14604. 'Ϋ' => 'Ϋ',
  14605. 'α�' => 'ά',
  14606. 'ε�' => 'έ',
  14607. 'η�' => 'ή',
  14608. 'ι�' => 'ί',
  14609. 'ϋ�' => 'ΰ',
  14610. 'ϊ' => 'ϊ',
  14611. 'ϋ' => 'ϋ',
  14612. 'ο�' => 'ό',
  14613. 'υ�' => '�',
  14614. 'ω�' => 'ώ',
  14615. 'ϒ�' => 'ϓ',
  14616. 'ϔ' => 'ϔ',
  14617. 'Ѐ' => 'Ѐ',
  14618. 'Ё' => '�',
  14619. 'Г�' => 'Ѓ',
  14620. 'Ї' => 'Ї',
  14621. 'К�' => 'Ќ',
  14622. 'Ѝ' => '�',
  14623. 'Ў' => 'Ў',
  14624. 'Й' => 'Й',
  14625. 'й' => 'й',
  14626. 'ѐ' => '�',
  14627. 'ё' => 'ё',
  14628. 'г�' => 'ѓ',
  14629. 'ї' => 'ї',
  14630. 'к�' => 'ќ',
  14631. 'ѝ' => '�',
  14632. 'ў' => 'ў',
  14633. 'Ѵ�' => 'Ѷ',
  14634. 'ѵ�' => 'ѷ',
  14635. 'Ӂ' => '�',
  14636. 'ӂ' => 'ӂ',
  14637. '�̆' => '�',
  14638. 'ӑ' => 'ӑ',
  14639. '�̈' => 'Ӓ',
  14640. 'ӓ' => 'ӓ',
  14641. 'Ӗ' => 'Ӗ',
  14642. 'ӗ' => 'ӗ',
  14643. 'Ӛ' => 'Ӛ',
  14644. 'ӛ' => 'ӛ',
  14645. 'Ӝ' => 'Ӝ',
  14646. 'ӝ' => '�',
  14647. 'Ӟ' => 'Ӟ',
  14648. 'ӟ' => 'ӟ',
  14649. 'Ӣ' => 'Ӣ',
  14650. 'ӣ' => 'ӣ',
  14651. 'Ӥ' => 'Ӥ',
  14652. 'ӥ' => 'ӥ',
  14653. 'Ӧ' => 'Ӧ',
  14654. 'ӧ' => 'ӧ',
  14655. 'Ӫ' => 'Ӫ',
  14656. 'ӫ' => 'ӫ',
  14657. 'Ӭ' => 'Ӭ',
  14658. '�̈' => 'ӭ',
  14659. 'Ӯ' => 'Ӯ',
  14660. 'ӯ' => 'ӯ',
  14661. 'Ӱ' => 'Ӱ',
  14662. 'ӱ' => 'ӱ',
  14663. 'Ӳ' => 'Ӳ',
  14664. 'ӳ' => 'ӳ',
  14665. 'Ӵ' => 'Ӵ',
  14666. 'ӵ' => 'ӵ',
  14667. 'Ӹ' => 'Ӹ',
  14668. 'ӹ' => 'ӹ',
  14669. 'آ' => 'آ',
  14670. 'أ' => 'أ',
  14671. 'ؤ' => 'ؤ',
  14672. 'إ' => 'إ',
  14673. 'ئ' => 'ئ',
  14674. 'Û•Ù”' => 'Û€',
  14675. 'Û�Ù”' => 'Û‚',
  14676. 'Û’Ù”' => 'Û“',
  14677. 'ऩ' => 'ऩ',
  14678. 'ऱ' => 'ऱ',
  14679. 'ऴ' => 'ऴ',
  14680. 'ো' => 'ো',
  14681. 'ৌ' => 'ৌ',
  14682. 'ୈ' => 'ୈ',
  14683. 'ୋ' => 'ୋ',
  14684. 'ୌ' => 'ୌ',
  14685. 'ஔ' => 'ஔ',
  14686. 'ொ' => 'ொ',
  14687. 'ோ' => 'ோ',
  14688. 'ௌ' => 'ௌ',
  14689. 'ై' => 'ై',
  14690. 'ೀ' => 'ೀ',
  14691. 'ೇ' => 'ೇ',
  14692. 'ೈ' => 'ೈ',
  14693. 'ೊ' => 'ೊ',
  14694. 'ೋ' => 'ೋ',
  14695. 'ൊ' => 'ൊ',
  14696. 'ോ' => 'ോ',
  14697. 'ൌ' => 'ൌ',
  14698. 'ේ' => 'ේ',
  14699. 'ෙ�' => 'ො',
  14700. 'ෝ' => '�',
  14701. 'ෞ' => 'ෞ',
  14702. 'ဦ' => 'ဦ',
  14703. 'ᬆ' => 'ᬆ',
  14704. 'ᬈ' => 'ᬈ',
  14705. 'ᬊ' => 'ᬊ',
  14706. 'ᬌ' => 'ᬌ',
  14707. '�ᬵ' => 'ᬎ',
  14708. 'ᬒ' => 'ᬒ',
  14709. 'ᬻ' => 'ᬻ',
  14710. 'ᬽ' => 'ᬽ',
  14711. 'ᭀ' => 'ᭀ',
  14712. 'ᭁ' => '�',
  14713. 'ᭃ' => 'ᭃ',
  14714. 'Ḁ' => 'Ḁ',
  14715. 'ḁ' => '�',
  14716. 'Ḃ' => 'Ḃ',
  14717. 'ḃ' => 'ḃ',
  14718. 'Ḅ' => 'Ḅ',
  14719. 'ḅ' => 'ḅ',
  14720. 'Ḇ' => 'Ḇ',
  14721. 'ḇ' => 'ḇ',
  14722. 'Ç�' => 'Ḉ',
  14723. 'ç�' => 'ḉ',
  14724. 'Ḋ' => 'Ḋ',
  14725. 'ḋ' => 'ḋ',
  14726. 'Ḍ' => 'Ḍ',
  14727. 'ḍ' => '�',
  14728. 'Ḏ' => 'Ḏ',
  14729. 'ḏ' => '�',
  14730. 'Ḑ' => '�',
  14731. 'ḑ' => 'ḑ',
  14732. 'Ḓ' => 'Ḓ',
  14733. 'ḓ' => 'ḓ',
  14734. 'Ḕ' => 'Ḕ',
  14735. 'ḕ' => 'ḕ',
  14736. 'Ē�' => 'Ḗ',
  14737. 'ē�' => 'ḗ',
  14738. 'Ḙ' => 'Ḙ',
  14739. 'ḙ' => 'ḙ',
  14740. 'Ḛ' => 'Ḛ',
  14741. 'ḛ' => 'ḛ',
  14742. 'Ḝ' => 'Ḝ',
  14743. 'ḝ' => '�',
  14744. 'Ḟ' => 'Ḟ',
  14745. 'ḟ' => 'ḟ',
  14746. 'Ḡ' => 'Ḡ',
  14747. 'ḡ' => 'ḡ',
  14748. 'Ḣ' => 'Ḣ',
  14749. 'ḣ' => 'ḣ',
  14750. 'Ḥ' => 'Ḥ',
  14751. 'ḥ' => 'ḥ',
  14752. 'Ḧ' => 'Ḧ',
  14753. 'ḧ' => 'ḧ',
  14754. 'Ḩ' => 'Ḩ',
  14755. 'ḩ' => 'ḩ',
  14756. 'Ḫ' => 'Ḫ',
  14757. 'ḫ' => 'ḫ',
  14758. 'Ḭ' => 'Ḭ',
  14759. 'ḭ' => 'ḭ',
  14760. '��' => 'Ḯ',
  14761. 'ï�' => 'ḯ',
  14762. 'K�' => 'Ḱ',
  14763. 'k�' => 'ḱ',
  14764. 'Ḳ' => 'Ḳ',
  14765. 'ḳ' => 'ḳ',
  14766. 'Ḵ' => 'Ḵ',
  14767. 'ḵ' => 'ḵ',
  14768. 'Ḷ' => 'Ḷ',
  14769. 'ḷ' => 'ḷ',
  14770. 'Ḹ' => 'Ḹ',
  14771. 'ḹ' => 'ḹ',
  14772. 'Ḻ' => 'Ḻ',
  14773. 'ḻ' => 'ḻ',
  14774. 'Ḽ' => 'Ḽ',
  14775. 'ḽ' => 'ḽ',
  14776. 'M�' => 'Ḿ',
  14777. 'm�' => 'ḿ',
  14778. 'Ṁ' => 'Ṁ',
  14779. 'ṁ' => '�',
  14780. 'Ṃ' => 'Ṃ',
  14781. 'ṃ' => 'ṃ',
  14782. 'Ṅ' => 'Ṅ',
  14783. 'ṅ' => 'ṅ',
  14784. 'Ṇ' => 'Ṇ',
  14785. 'ṇ' => 'ṇ',
  14786. 'Ṉ' => 'Ṉ',
  14787. 'ṉ' => 'ṉ',
  14788. 'Ṋ' => 'Ṋ',
  14789. 'ṋ' => 'ṋ',
  14790. 'Õ�' => 'Ṍ',
  14791. 'õ�' => '�',
  14792. 'Ṏ' => 'Ṏ',
  14793. 'ṏ' => '�',
  14794. 'Ṑ' => '�',
  14795. '�̀' => 'ṑ',
  14796. 'Ō�' => 'Ṓ',
  14797. '��' => 'ṓ',
  14798. 'P�' => 'Ṕ',
  14799. 'p�' => 'ṕ',
  14800. 'Ṗ' => 'Ṗ',
  14801. 'ṗ' => 'ṗ',
  14802. 'Ṙ' => 'Ṙ',
  14803. 'ṙ' => 'ṙ',
  14804. 'Ṛ' => 'Ṛ',
  14805. 'ṛ' => 'ṛ',
  14806. 'Ṝ' => 'Ṝ',
  14807. 'ṝ' => '�',
  14808. 'Ṟ' => 'Ṟ',
  14809. 'ṟ' => 'ṟ',
  14810. 'Ṡ' => 'Ṡ',
  14811. 'ṡ' => 'ṡ',
  14812. 'SÌ£' => 'á¹¢',
  14813. 'ṣ' => 'ṣ',
  14814. 'Ṥ' => 'Ṥ',
  14815. 'ṥ' => 'ṥ',
  14816. 'Ṧ' => 'Ṧ',
  14817. 'ṧ' => 'ṧ',
  14818. 'Ṩ' => 'Ṩ',
  14819. 'ṩ' => 'ṩ',
  14820. 'Ṫ' => 'Ṫ',
  14821. 'ṫ' => 'ṫ',
  14822. 'Ṭ' => 'Ṭ',
  14823. 'ṭ' => 'ṭ',
  14824. 'Ṯ' => 'Ṯ',
  14825. 'ṯ' => 'ṯ',
  14826. 'TÌ­' => 'á¹°',
  14827. 'tÌ­' => 'á¹±',
  14828. 'Ṳ' => 'Ṳ',
  14829. 'ṳ' => 'ṳ',
  14830. 'Ṵ' => 'Ṵ',
  14831. 'ṵ' => 'ṵ',
  14832. 'UÌ­' => 'á¹¶',
  14833. 'uÌ­' => 'á¹·',
  14834. 'Ũ�' => 'Ṹ',
  14835. 'ũ�' => 'ṹ',
  14836. 'Ṻ' => 'Ṻ',
  14837. 'ṻ' => 'ṻ',
  14838. 'Ṽ' => 'Ṽ',
  14839. 'ṽ' => 'ṽ',
  14840. 'VÌ£' => 'á¹¾',
  14841. 'ṿ' => 'ṿ',
  14842. 'Ẁ' => 'Ẁ',
  14843. 'ẁ' => '�',
  14844. 'W�' => 'Ẃ',
  14845. 'w�' => 'ẃ',
  14846. 'Ẅ' => 'Ẅ',
  14847. 'ẅ' => 'ẅ',
  14848. 'Ẇ' => 'Ẇ',
  14849. 'ẇ' => 'ẇ',
  14850. 'Ẉ' => 'Ẉ',
  14851. 'ẉ' => 'ẉ',
  14852. 'Ẋ' => 'Ẋ',
  14853. 'ẋ' => 'ẋ',
  14854. 'Ẍ' => 'Ẍ',
  14855. 'ẍ' => '�',
  14856. 'Ẏ' => 'Ẏ',
  14857. 'ẏ' => '�',
  14858. 'Ẑ' => '�',
  14859. 'ẑ' => 'ẑ',
  14860. 'Ẓ' => 'Ẓ',
  14861. 'ẓ' => 'ẓ',
  14862. 'Ẕ' => 'Ẕ',
  14863. 'ẕ' => 'ẕ',
  14864. 'ẖ' => 'ẖ',
  14865. 'ẗ' => 'ẗ',
  14866. 'ẘ' => 'ẘ',
  14867. 'ẙ' => 'ẙ',
  14868. 'ẛ' => 'ẛ',
  14869. 'Ạ' => 'Ạ',
  14870. 'ạ' => 'ạ',
  14871. 'Ả' => 'Ả',
  14872. 'ả' => 'ả',
  14873. 'Â�' => 'Ấ',
  14874. 'â�' => 'ấ',
  14875. 'Ầ' => 'Ầ',
  14876. 'ầ' => 'ầ',
  14877. 'Ẩ' => 'Ẩ',
  14878. 'ẩ' => 'ẩ',
  14879. 'Ẫ' => 'Ẫ',
  14880. 'ẫ' => 'ẫ',
  14881. 'Ậ' => 'Ậ',
  14882. 'ậ' => 'ậ',
  14883. 'Ă�' => 'Ắ',
  14884. 'ă�' => 'ắ',
  14885. 'Ằ' => 'Ằ',
  14886. 'ằ' => 'ằ',
  14887. 'Ẳ' => 'Ẳ',
  14888. 'ẳ' => 'ẳ',
  14889. 'Ẵ' => 'Ẵ',
  14890. 'ẵ' => 'ẵ',
  14891. 'Ặ' => 'Ặ',
  14892. 'ặ' => 'ặ',
  14893. 'Ẹ' => 'Ẹ',
  14894. 'ẹ' => 'ẹ',
  14895. 'Ẻ' => 'Ẻ',
  14896. 'ẻ' => 'ẻ',
  14897. 'Ẽ' => 'Ẽ',
  14898. 'ẽ' => 'ẽ',
  14899. 'Ê�' => 'Ế',
  14900. 'ê�' => 'ế',
  14901. 'Ề' => 'Ề',
  14902. 'ề' => '�',
  14903. 'Ể' => 'Ể',
  14904. 'ể' => 'ể',
  14905. 'Ễ' => 'Ễ',
  14906. 'ễ' => 'ễ',
  14907. 'Ệ' => 'Ệ',
  14908. 'ệ' => 'ệ',
  14909. 'Ỉ' => 'Ỉ',
  14910. 'ỉ' => 'ỉ',
  14911. 'Ị' => 'Ị',
  14912. 'ị' => 'ị',
  14913. 'Ọ' => 'Ọ',
  14914. 'ọ' => '�',
  14915. 'Ỏ' => 'Ỏ',
  14916. 'ỏ' => '�',
  14917. 'Ô�' => '�',
  14918. 'ô�' => 'ố',
  14919. 'Ồ' => 'Ồ',
  14920. 'ồ' => 'ồ',
  14921. 'Ổ' => 'Ổ',
  14922. 'ổ' => 'ổ',
  14923. 'Ỗ' => 'Ỗ',
  14924. 'ỗ' => 'ỗ',
  14925. 'Ộ' => 'Ộ',
  14926. '�̂' => 'ộ',
  14927. 'Ơ�' => 'Ớ',
  14928. 'ơ�' => 'ớ',
  14929. 'Ờ' => 'Ờ',
  14930. 'ờ' => '�',
  14931. 'Ở' => 'Ở',
  14932. 'ở' => 'ở',
  14933. 'Ỡ' => 'Ỡ',
  14934. 'ỡ' => 'ỡ',
  14935. 'Ợ' => 'Ợ',
  14936. 'ợ' => 'ợ',
  14937. 'Ụ' => 'Ụ',
  14938. 'ụ' => 'ụ',
  14939. 'Ủ' => 'Ủ',
  14940. 'ủ' => 'ủ',
  14941. 'Ư�' => 'Ứ',
  14942. 'ư�' => 'ứ',
  14943. 'Ừ' => 'Ừ',
  14944. 'ừ' => 'ừ',
  14945. 'Ử' => 'Ử',
  14946. 'ử' => 'ử',
  14947. 'Ữ' => 'Ữ',
  14948. 'ữ' => 'ữ',
  14949. 'Ự' => 'Ự',
  14950. 'ự' => 'ự',
  14951. 'Ỳ' => 'Ỳ',
  14952. 'ỳ' => 'ỳ',
  14953. 'YÌ£' => 'á»´',
  14954. 'ỵ' => 'ỵ',
  14955. 'Ỷ' => 'Ỷ',
  14956. 'ỷ' => 'ỷ',
  14957. 'Ỹ' => 'Ỹ',
  14958. 'ỹ' => 'ỹ',
  14959. 'ἀ' => 'ἀ',
  14960. 'ἁ' => '�',
  14961. 'ἂ' => 'ἂ',
  14962. '�̀' => 'ἃ',
  14963. 'ἀ�' => 'ἄ',
  14964. '��' => 'ἅ',
  14965. 'ἆ' => 'ἆ',
  14966. '�͂' => 'ἇ',
  14967. 'Ἀ' => 'Ἀ',
  14968. 'Ἁ' => 'Ἁ',
  14969. 'Ἂ' => 'Ἂ',
  14970. 'Ἃ' => 'Ἃ',
  14971. 'Ἀ�' => 'Ἄ',
  14972. 'Ἁ�' => '�',
  14973. 'Ἆ' => 'Ἆ',
  14974. 'Ἇ' => '�',
  14975. 'ἐ' => '�',
  14976. 'ἑ' => 'ἑ',
  14977. '�̀' => 'ἒ',
  14978. 'ἓ' => 'ἓ',
  14979. '��' => 'ἔ',
  14980. 'ἑ�' => 'ἕ',
  14981. 'Ἐ' => 'Ἐ',
  14982. 'Ἑ' => 'Ἑ',
  14983. 'Ἒ' => 'Ἒ',
  14984. 'Ἓ' => 'Ἓ',
  14985. 'Ἐ�' => 'Ἔ',
  14986. 'Ἑ�' => '�',
  14987. 'ἠ' => 'ἠ',
  14988. 'ἡ' => 'ἡ',
  14989. 'ἢ' => 'ἢ',
  14990. 'ἣ' => 'ἣ',
  14991. 'ἠ�' => 'ἤ',
  14992. 'ἡ�' => 'ἥ',
  14993. 'ἦ' => 'ἦ',
  14994. 'ἧ' => 'ἧ',
  14995. 'Ἠ' => 'Ἠ',
  14996. 'Ἡ' => 'Ἡ',
  14997. 'Ἢ' => 'Ἢ',
  14998. 'Ἣ' => 'Ἣ',
  14999. 'Ἠ�' => 'Ἤ',
  15000. 'Ἡ�' => 'Ἥ',
  15001. 'Ἦ' => 'Ἦ',
  15002. 'Ἧ' => 'Ἧ',
  15003. 'ἰ' => 'ἰ',
  15004. 'ἱ' => 'ἱ',
  15005. 'á¼°Ì€' => 'á¼²',
  15006. 'ἳ' => 'ἳ',
  15007. 'ἰ�' => 'ἴ',
  15008. 'ἱ�' => 'ἵ',
  15009. 'á¼°Í‚' => 'á¼¶',
  15010. 'ἷ' => 'ἷ',
  15011. 'Ἰ' => 'Ἰ',
  15012. 'Ἱ' => 'Ἱ',
  15013. 'Ἲ' => 'Ἲ',
  15014. 'Ἳ' => 'Ἳ',
  15015. 'Ἰ�' => 'Ἴ',
  15016. 'Ἱ�' => 'Ἵ',
  15017. 'Ἶ' => 'Ἶ',
  15018. 'Ἷ' => 'Ἷ',
  15019. 'ὀ' => 'ὀ',
  15020. 'ὁ' => '�',
  15021. 'ὂ' => 'ὂ',
  15022. '�̀' => 'ὃ',
  15023. 'ὀ�' => 'ὄ',
  15024. '��' => 'ὅ',
  15025. 'Ὀ' => 'Ὀ',
  15026. 'Ὁ' => 'Ὁ',
  15027. 'Ὂ' => 'Ὂ',
  15028. 'Ὃ' => 'Ὃ',
  15029. 'Ὀ�' => 'Ὄ',
  15030. 'Ὁ�' => '�',
  15031. 'ὐ' => '�',
  15032. 'ὑ' => 'ὑ',
  15033. '�̀' => 'ὒ',
  15034. 'ὓ' => 'ὓ',
  15035. '��' => 'ὔ',
  15036. 'ὑ�' => 'ὕ',
  15037. '�͂' => 'ὖ',
  15038. 'ὗ' => 'ὗ',
  15039. 'Ὑ' => 'Ὑ',
  15040. 'Ὓ' => 'Ὓ',
  15041. 'Ὑ�' => '�',
  15042. 'Ὗ' => 'Ὗ',
  15043. 'ὠ' => 'ὠ',
  15044. 'ὡ' => 'ὡ',
  15045. 'ὢ' => 'ὢ',
  15046. 'ὣ' => 'ὣ',
  15047. 'ὠ�' => 'ὤ',
  15048. 'ὡ�' => 'ὥ',
  15049. 'ὦ' => 'ὦ',
  15050. 'ὧ' => 'ὧ',
  15051. 'Ὠ' => 'Ὠ',
  15052. 'Ὡ' => 'Ὡ',
  15053. 'Ὢ' => 'Ὢ',
  15054. 'Ὣ' => 'Ὣ',
  15055. 'Ὠ�' => 'Ὤ',
  15056. 'Ὡ�' => 'Ὥ',
  15057. 'Ὦ' => 'Ὦ',
  15058. 'Ὧ' => 'Ὧ',
  15059. 'ὰ' => 'ὰ',
  15060. 'ὲ' => 'ὲ',
  15061. 'ὴ' => 'ὴ',
  15062. 'ὶ' => 'ὶ',
  15063. 'ὸ' => 'ὸ',
  15064. 'ὺ' => 'ὺ',
  15065. 'ὼ' => 'ὼ',
  15066. 'ᾀ' => 'ᾀ',
  15067. '�ͅ' => '�',
  15068. 'ᾂ' => 'ᾂ',
  15069. 'ᾃ' => 'ᾃ',
  15070. 'ᾄ' => 'ᾄ',
  15071. 'á¼…Í…' => 'á¾…',
  15072. 'ᾆ' => 'ᾆ',
  15073. 'ᾇ' => 'ᾇ',
  15074. 'ᾈ' => 'ᾈ',
  15075. 'ᾉ' => 'ᾉ',
  15076. 'ᾊ' => 'ᾊ',
  15077. 'ᾋ' => 'ᾋ',
  15078. 'ᾌ' => 'ᾌ',
  15079. '�ͅ' => '�',
  15080. 'ᾎ' => 'ᾎ',
  15081. '�ͅ' => '�',
  15082. 'ᾐ' => '�',
  15083. 'ᾑ' => 'ᾑ',
  15084. 'ᾒ' => 'ᾒ',
  15085. 'ᾓ' => 'ᾓ',
  15086. 'ᾔ' => 'ᾔ',
  15087. 'ᾕ' => 'ᾕ',
  15088. 'ᾖ' => 'ᾖ',
  15089. 'á¼§Í…' => 'á¾—',
  15090. 'ᾘ' => 'ᾘ',
  15091. 'ᾙ' => 'ᾙ',
  15092. 'ᾚ' => 'ᾚ',
  15093. 'ᾛ' => 'ᾛ',
  15094. 'ᾜ' => 'ᾜ',
  15095. 'ᾝ' => '�',
  15096. 'ᾞ' => 'ᾞ',
  15097. 'ᾟ' => 'ᾟ',
  15098. 'á½ Í…' => 'á¾ ',
  15099. 'ᾡ' => 'ᾡ',
  15100. 'ᾢ' => 'ᾢ',
  15101. 'ᾣ' => 'ᾣ',
  15102. 'ᾤ' => 'ᾤ',
  15103. 'ᾥ' => 'ᾥ',
  15104. 'ᾦ' => 'ᾦ',
  15105. 'á½§Í…' => 'á¾§',
  15106. 'ᾨ' => 'ᾨ',
  15107. 'ᾩ' => 'ᾩ',
  15108. 'ᾪ' => 'ᾪ',
  15109. 'ᾫ' => 'ᾫ',
  15110. 'ᾬ' => 'ᾬ',
  15111. 'á½­Í…' => 'á¾­',
  15112. 'ᾮ' => 'ᾮ',
  15113. 'ᾯ' => 'ᾯ',
  15114. 'ᾰ' => 'ᾰ',
  15115. 'ᾱ' => 'ᾱ',
  15116. 'á½°Í…' => 'á¾²',
  15117. 'ᾳ' => 'ᾳ',
  15118. 'ᾴ' => 'ᾴ',
  15119. 'ᾶ' => 'ᾶ',
  15120. 'á¾¶Í…' => 'á¾·',
  15121. 'Ᾰ' => 'Ᾰ',
  15122. 'Ᾱ' => 'Ᾱ',
  15123. 'Ὰ' => 'Ὰ',
  15124. 'ᾼ' => 'ᾼ',
  15125. '῁' => '�',
  15126. 'á½´Í…' => 'á¿‚',
  15127. 'ῃ' => 'ῃ',
  15128. 'ῄ' => 'ῄ',
  15129. 'ῆ' => 'ῆ',
  15130. 'ῇ' => 'ῇ',
  15131. 'Ὲ' => 'Ὲ',
  15132. 'Ὴ' => 'Ὴ',
  15133. 'ῌ' => 'ῌ',
  15134. '῍' => '�',
  15135. '᾿�' => '῎',
  15136. '῏' => '�',
  15137. 'ῐ' => '�',
  15138. 'ῑ' => 'ῑ',
  15139. 'ÏŠÌ€' => 'á¿’',
  15140. 'ῖ' => 'ῖ',
  15141. 'ÏŠÍ‚' => 'á¿—',
  15142. 'Ῐ' => 'Ῐ',
  15143. 'Ῑ' => 'Ῑ',
  15144. 'Ὶ' => 'Ὶ',
  15145. '῝' => '�',
  15146. '῾�' => '῞',
  15147. '῟' => '῟',
  15148. 'ῠ' => 'ῠ',
  15149. 'Ï…Ì„' => 'á¿¡',
  15150. 'ῢ' => 'ῢ',
  15151. '�̓' => 'ῤ',
  15152. '�̔' => 'ῥ',
  15153. 'ῦ' => 'ῦ',
  15154. 'ῧ' => 'ῧ',
  15155. 'Ῠ' => 'Ῠ',
  15156. 'Ῡ' => 'Ῡ',
  15157. 'Ὺ' => 'Ὺ',
  15158. 'Ῥ' => 'Ῥ',
  15159. '῭' => '῭',
  15160. 'ῲ' => 'ῲ',
  15161. 'ῳ' => 'ῳ',
  15162. 'ÏŽÍ…' => 'á¿´',
  15163. 'ῶ' => 'ῶ',
  15164. 'á¿¶Í…' => 'á¿·',
  15165. 'Ὸ' => 'Ὸ',
  15166. 'Ὼ' => 'Ὼ',
  15167. 'ῼ' => 'ῼ',
  15168. '�̸' => '↚',
  15169. '↛' => '↛',
  15170. '↮' => '↮',
  15171. '�̸' => '�',
  15172. '⇎' => '⇎',
  15173. '⇏' => '�',
  15174. '∄' => '∄',
  15175. '∉' => '∉',
  15176. '∌' => '∌',
  15177. '∤' => '∤',
  15178. '∦' => '∦',
  15179. '≁' => '�',
  15180. '≄' => '≄',
  15181. '≇' => '≇',
  15182. '≉' => '≉',
  15183. '≠' => '≠',
  15184. '≢' => '≢',
  15185. '�̸' => '≭',
  15186. '≮' => '≮',
  15187. '≯' => '≯',
  15188. '≰' => '≰',
  15189. '≱' => '≱',
  15190. '≴' => '≴',
  15191. '≵' => '≵',
  15192. '≸' => '≸',
  15193. '≹' => '≹',
  15194. '⊀' => '⊀',
  15195. '⊁' => '�',
  15196. '⊄' => '⊄',
  15197. '⊅' => '⊅',
  15198. '⊈' => '⊈',
  15199. '⊉' => '⊉',
  15200. '⊬' => '⊬',
  15201. '⊭' => '⊭',
  15202. '⊮' => '⊮',
  15203. '⊯' => '⊯',
  15204. '⋠' => '⋠',
  15205. '⋡' => '⋡',
  15206. '⋢' => '⋢',
  15207. '⋣' => '⋣',
  15208. '⋪' => '⋪',
  15209. '⋫' => '⋫',
  15210. '⋬' => '⋬',
  15211. '⋭' => '⋭',
  15212. '�゙' => '�',
  15213. '�゙' => '�',
  15214. '�゙' => '�',
  15215. '�゙' => '�',
  15216. '�゙' => '�',
  15217. '�゙' => '�',
  15218. '�゙' => '�',
  15219. '�゙' => '�',
  15220. '�゙' => '�',
  15221. '�゙' => '�',
  15222. '�゙' => '�',
  15223. '�゙' => '�',
  15224. '�゙' => '�',
  15225. '�゙' => '�',
  15226. '�゙' => '�',
  15227. '�゙' => '�',
  15228. '�゚' => '�',
  15229. '�゙' => '�',
  15230. '�゚' => '�',
  15231. '�゙' => '�',
  15232. '�゚' => '�',
  15233. '�゙' => '�',
  15234. '�゚' => '�',
  15235. '�゙' => '�',
  15236. '�゚' => '�',
  15237. '�゙' => 'ゔ',
  15238. '�゙' => 'ゞ',
  15239. 'ガ' => 'ガ',
  15240. 'ã‚­ã‚™' => 'ã‚®',
  15241. 'グ' => 'グ',
  15242. 'ゲ' => 'ゲ',
  15243. 'ゴ' => 'ゴ',
  15244. 'ザ' => 'ザ',
  15245. 'ジ' => 'ジ',
  15246. 'ズ' => 'ズ',
  15247. 'ゼ' => 'ゼ',
  15248. 'ゾ' => 'ゾ',
  15249. 'ダ' => 'ダ',
  15250. '�゙' => 'ヂ',
  15251. 'ヅ' => 'ヅ',
  15252. 'デ' => 'デ',
  15253. 'ド' => 'ド',
  15254. '�゙' => '�',
  15255. '�゚' => 'パ',
  15256. 'ビ' => 'ビ',
  15257. 'ピ' => 'ピ',
  15258. 'ブ' => 'ブ',
  15259. 'プ' => 'プ',
  15260. 'ベ' => 'ベ',
  15261. 'ペ' => 'ペ',
  15262. 'ボ' => 'ボ',
  15263. 'ポ' => '�',
  15264. 'ヴ' => 'ヴ',
  15265. 'ヷ' => 'ヷ',
  15266. 'ヸ' => 'ヸ',
  15267. 'ヹ' => 'ヹ',
  15268. 'ヺ' => 'ヺ',
  15269. 'ヾ' => 'ヾ',
  15270. '𑂚' => '𑂚',
  15271. '𑂜' => '𑂜',
  15272. '𑂫' => '𑂫',
  15273. '𑄮' => '𑄮',
  15274. '𑄯' => '𑄯',
  15275. '�𑌾' => '�',
  15276. '��' => '�',
  15277. '𑒻' => '𑒻',
  15278. '𑒼' => '𑒼',
  15279. '𑒾' => '𑒾',
  15280. '𑖺' => '𑖺',
  15281. '𑖻' => '𑖻',
  15282. '𑤸' => '𑤸',
  15283. );
  15284. <?php
  15285. return array (
  15286. ' ' => ' ',
  15287. '¨' => ' ̈',
  15288. 'ª' => 'a',
  15289. '¯' => ' ̄',
  15290. '²' => '2',
  15291. '³' => '3',
  15292. '´' => ' �',
  15293. 'µ' => 'μ',
  15294. '¸' => ' ̧',
  15295. '¹' => '1',
  15296. 'º' => 'o',
  15297. '¼' => '1�4',
  15298. '½' => '1�2',
  15299. '¾' => '3�4',
  15300. 'IJ' => 'IJ',
  15301. 'ij' => 'ij',
  15302. 'Ŀ' => 'L·',
  15303. 'ŀ' => 'l·',
  15304. 'ʼn' => 'ʼn',
  15305. 'Å¿' => 's',
  15306. 'DŽ' => 'DŽ',
  15307. 'Dž' => 'Dž',
  15308. 'dž' => 'dž',
  15309. 'LJ' => 'LJ',
  15310. 'Lj' => 'Lj',
  15311. 'lj' => 'lj',
  15312. 'ÇŠ' => 'NJ',
  15313. 'Ç‹' => 'Nj',
  15314. 'nj' => 'nj',
  15315. 'DZ' => 'DZ',
  15316. 'Dz' => 'Dz',
  15317. 'dz' => 'dz',
  15318. 'ʰ' => 'h',
  15319. 'ʱ' => 'ɦ',
  15320. 'ʲ' => 'j',
  15321. 'ʳ' => 'r',
  15322. 'ʴ' => 'ɹ',
  15323. 'ʵ' => 'ɻ',
  15324. 'ʶ' => '�',
  15325. 'Ê·' => 'w',
  15326. 'ʸ' => 'y',
  15327. '˘' => ' ̆',
  15328. '˙' => ' ̇',
  15329. 'Ëš' => ' ÌŠ',
  15330. '˛' => ' ̨',
  15331. '˜' => ' ̃',
  15332. '�' => ' ̋',
  15333. 'Ë ' => 'É£',
  15334. 'Ë¡' => 'l',
  15335. 'Ë¢' => 's',
  15336. 'Ë£' => 'x',
  15337. 'ˤ' => 'ʕ',
  15338. 'ͺ' => ' ͅ',
  15339. '΄' => ' �',
  15340. '΅' => ' ̈�',
  15341. '�' => 'β',
  15342. 'ϑ' => 'θ',
  15343. 'Ï’' => 'Î¥',
  15344. 'ϓ' => 'Υ�',
  15345. 'ϔ' => 'Ϋ',
  15346. 'ϕ' => 'φ',
  15347. 'Ï–' => 'Ï€',
  15348. 'ϰ' => 'κ',
  15349. 'ϱ' => '�',
  15350. 'ϲ' => 'ς',
  15351. 'ϴ' => 'Θ',
  15352. 'ϵ' => 'ε',
  15353. 'Ϲ' => 'Σ',
  15354. 'Ö‡' => 'Õ¥Ö‚',
  15355. 'ٵ' => 'اٴ',
  15356. 'ٶ' => 'وٴ',
  15357. 'Ù·' => 'Û‡Ù´',
  15358. 'ٸ' => 'يٴ',
  15359. 'ำ' => '�า',
  15360. 'ຳ' => '�າ',
  15361. 'ໜ' => 'ຫນ',
  15362. '�' => 'ຫມ',
  15363. '༌' => '་',
  15364. 'ཷ' => 'ྲཱྀ',
  15365. 'ཹ' => 'ླཱྀ',
  15366. 'ჼ' => 'ნ',
  15367. 'á´¬' => 'A',
  15368. 'ᴭ' => 'Æ',
  15369. 'á´®' => 'B',
  15370. 'á´°' => 'D',
  15371. 'á´±' => 'E',
  15372. 'á´²' => 'ÆŽ',
  15373. 'á´³' => 'G',
  15374. 'á´´' => 'H',
  15375. 'á´µ' => 'I',
  15376. 'á´¶' => 'J',
  15377. 'á´·' => 'K',
  15378. 'á´¸' => 'L',
  15379. 'á´¹' => 'M',
  15380. 'á´º' => 'N',
  15381. 'á´¼' => 'O',
  15382. 'á´½' => 'È¢',
  15383. 'á´¾' => 'P',
  15384. 'á´¿' => 'R',
  15385. 'áµ€' => 'T',
  15386. '�' => 'U',
  15387. 'ᵂ' => 'W',
  15388. 'ᵃ' => 'a',
  15389. 'ᵄ' => '�',
  15390. 'áµ…' => 'É‘',
  15391. 'ᵆ' => 'ᴂ',
  15392. 'ᵇ' => 'b',
  15393. 'ᵈ' => 'd',
  15394. 'ᵉ' => 'e',
  15395. 'ᵊ' => 'ə',
  15396. 'ᵋ' => 'ɛ',
  15397. 'ᵌ' => 'ɜ',
  15398. '�' => 'g',
  15399. '�' => 'k',
  15400. '�' => 'm',
  15401. 'ᵑ' => 'ŋ',
  15402. 'áµ’' => 'o',
  15403. 'ᵓ' => 'ɔ',
  15404. 'áµ”' => 'á´–',
  15405. 'ᵕ' => 'ᴗ',
  15406. 'áµ–' => 'p',
  15407. 'áµ—' => 't',
  15408. 'ᵘ' => 'u',
  15409. 'áµ™' => 'á´�',
  15410. 'ᵚ' => 'ɯ',
  15411. 'áµ›' => 'v',
  15412. 'ᵜ' => 'ᴥ',
  15413. '�' => 'β',
  15414. 'ᵞ' => 'γ',
  15415. 'ᵟ' => 'δ',
  15416. 'ᵠ' => 'φ',
  15417. 'ᵡ' => 'χ',
  15418. 'áµ¢' => 'i',
  15419. 'áµ£' => 'r',
  15420. 'ᵤ' => 'u',
  15421. 'áµ¥' => 'v',
  15422. 'ᵦ' => 'β',
  15423. 'ᵧ' => 'γ',
  15424. 'ᵨ' => '�',
  15425. 'ᵩ' => 'φ',
  15426. 'ᵪ' => 'χ',
  15427. 'ᵸ' => 'н',
  15428. 'á¶›' => 'É’',
  15429. 'ᶜ' => 'c',
  15430. '�' => 'ɕ',
  15431. 'ᶞ' => 'ð',
  15432. 'ᶟ' => 'ɜ',
  15433. 'á¶ ' => 'f',
  15434. 'á¶¡' => 'ÉŸ',
  15435. 'á¶¢' => 'É¡',
  15436. 'á¶£' => 'É¥',
  15437. 'ᶤ' => 'ɨ',
  15438. 'á¶¥' => 'É©',
  15439. 'ᶦ' => 'ɪ',
  15440. 'á¶§' => 'áµ»',
  15441. 'ᶨ' => '�',
  15442. 'á¶©' => 'É­',
  15443. 'ᶪ' => 'ᶅ',
  15444. 'á¶«' => 'ÊŸ',
  15445. 'ᶬ' => 'ɱ',
  15446. 'ᶭ' => 'ɰ',
  15447. 'ᶮ' => 'ɲ',
  15448. 'ᶯ' => 'ɳ',
  15449. 'á¶°' => 'É´',
  15450. 'ᶱ' => 'ɵ',
  15451. 'ᶲ' => 'ɸ',
  15452. 'á¶³' => 'Ê‚',
  15453. 'ᶴ' => 'ʃ',
  15454. 'á¶µ' => 'Æ«',
  15455. 'ᶶ' => 'ʉ',
  15456. 'á¶·' => 'ÊŠ',
  15457. 'ᶸ' => 'ᴜ',
  15458. 'á¶¹' => 'Ê‹',
  15459. 'ᶺ' => 'ʌ',
  15460. 'á¶»' => 'z',
  15461. 'ᶼ' => '�',
  15462. 'á¶½' => 'Ê‘',
  15463. 'á¶¾' => 'Ê’',
  15464. 'ᶿ' => 'θ',
  15465. 'ẚ' => 'aʾ',
  15466. 'ẛ' => 'ṡ',
  15467. 'á¾½' => ' Ì“',
  15468. '᾿' => ' ̓',
  15469. 'á¿€' => ' Í‚',
  15470. '�' => ' ̈͂',
  15471. '�' => ' ̓̀',
  15472. '῎' => ' ̓�',
  15473. '�' => ' ̓͂',
  15474. '�' => ' ̔̀',
  15475. '῞' => ' ̔�',
  15476. '῟' => ' ̔͂',
  15477. '῭' => ' ̈̀',
  15478. '΅' => ' ̈�',
  15479. '´' => ' �',
  15480. '῾' => ' ̔',
  15481. ' ' => ' ',
  15482. '�' => ' ',
  15483. ' ' => ' ',
  15484. ' ' => ' ',
  15485. ' ' => ' ',
  15486. ' ' => ' ',
  15487. ' ' => ' ',
  15488. ' ' => ' ',
  15489. ' ' => ' ',
  15490. ' ' => ' ',
  15491. ' ' => ' ',
  15492. '‑' => '�',
  15493. '‗' => ' ̳',
  15494. '․' => '.',
  15495. '‥' => '..',
  15496. '…' => '...',
  15497. ' ' => ' ',
  15498. '″' => '′′',
  15499. '‴' => '′′′',
  15500. '‶' => '‵‵',
  15501. '‷' => '‵‵‵',
  15502. '‼' => '!!',
  15503. '‾' => ' ̅',
  15504. '�' => '??',
  15505. '�' => '?!',
  15506. '�' => '!?',
  15507. '�' => '′′′′',
  15508. '�' => ' ',
  15509. '�' => '0',
  15510. '�' => 'i',
  15511. '�' => '4',
  15512. '�' => '5',
  15513. '�' => '6',
  15514. '�' => '7',
  15515. '�' => '8',
  15516. '�' => '9',
  15517. '�' => '+',
  15518. '�' => '−',
  15519. '�' => '=',
  15520. '�' => '(',
  15521. '�' => ')',
  15522. '�' => 'n',
  15523. 'â‚€' => '0',
  15524. '�' => '1',
  15525. 'â‚‚' => '2',
  15526. '₃' => '3',
  15527. 'â‚„' => '4',
  15528. 'â‚…' => '5',
  15529. '₆' => '6',
  15530. '₇' => '7',
  15531. '₈' => '8',
  15532. '₉' => '9',
  15533. '₊' => '+',
  15534. '₋' => '−',
  15535. '₌' => '=',
  15536. '�' => '(',
  15537. '₎' => ')',
  15538. '�' => 'a',
  15539. 'â‚‘' => 'e',
  15540. 'â‚’' => 'o',
  15541. 'â‚“' => 'x',
  15542. 'â‚”' => 'É™',
  15543. 'â‚•' => 'h',
  15544. 'â‚–' => 'k',
  15545. 'â‚—' => 'l',
  15546. 'ₘ' => 'm',
  15547. 'â‚™' => 'n',
  15548. 'ₚ' => 'p',
  15549. 'â‚›' => 's',
  15550. 'ₜ' => 't',
  15551. '₨' => 'Rs',
  15552. 'â„€' => 'a/c',
  15553. '�' => 'a/s',
  15554. 'â„‚' => 'C',
  15555. '℃' => '°C',
  15556. 'â„…' => 'c/o',
  15557. '℆' => 'c/u',
  15558. 'ℇ' => '�',
  15559. '℉' => '°F',
  15560. 'ℊ' => 'g',
  15561. 'â„‹' => 'H',
  15562. 'ℌ' => 'H',
  15563. '�' => 'H',
  15564. 'ℎ' => 'h',
  15565. '�' => 'ħ',
  15566. '�' => 'I',
  15567. 'â„‘' => 'I',
  15568. 'â„’' => 'L',
  15569. 'â„“' => 'l',
  15570. 'â„•' => 'N',
  15571. 'â„–' => 'No',
  15572. 'â„™' => 'P',
  15573. 'ℚ' => 'Q',
  15574. 'â„›' => 'R',
  15575. 'ℜ' => 'R',
  15576. '�' => 'R',
  15577. 'â„ ' => 'SM',
  15578. 'â„¡' => 'TEL',
  15579. 'â„¢' => 'TM',
  15580. 'ℤ' => 'Z',
  15581. 'ℨ' => 'Z',
  15582. 'ℬ' => 'B',
  15583. 'â„­' => 'C',
  15584. 'ℯ' => 'e',
  15585. 'â„°' => 'E',
  15586. 'ℱ' => 'F',
  15587. 'ℳ' => 'M',
  15588. 'â„´' => 'o',
  15589. 'ℵ' => '�',
  15590. 'ℶ' => 'ב',
  15591. 'â„·' => '×’',
  15592. 'ℸ' => 'ד',
  15593. 'ℹ' => 'i',
  15594. 'â„»' => 'FAX',
  15595. 'ℼ' => 'π',
  15596. 'ℽ' => 'γ',
  15597. 'ℾ' => 'Γ',
  15598. 'ℿ' => 'Π',
  15599. '⅀' => '∑',
  15600. 'â……' => 'D',
  15601. 'â…†' => 'd',
  15602. 'â…‡' => 'e',
  15603. 'â…ˆ' => 'i',
  15604. 'â…‰' => 'j',
  15605. '�' => '1�7',
  15606. '⅑' => '1�9',
  15607. '⅒' => '1�10',
  15608. '⅓' => '1�3',
  15609. '⅔' => '2�3',
  15610. '⅕' => '1�5',
  15611. '⅖' => '2�5',
  15612. '⅗' => '3�5',
  15613. '⅘' => '4�5',
  15614. '⅙' => '1�6',
  15615. '⅚' => '5�6',
  15616. '⅛' => '1�8',
  15617. '⅜' => '3�8',
  15618. '�' => '5�8',
  15619. '⅞' => '7�8',
  15620. '⅟' => '1�',
  15621. 'â… ' => 'I',
  15622. 'â…¡' => 'II',
  15623. 'â…¢' => 'III',
  15624. 'â…£' => 'IV',
  15625. 'â…¤' => 'V',
  15626. 'â…¥' => 'VI',
  15627. 'â…¦' => 'VII',
  15628. 'â…§' => 'VIII',
  15629. 'â…¨' => 'IX',
  15630. 'â…©' => 'X',
  15631. 'â…ª' => 'XI',
  15632. 'â…«' => 'XII',
  15633. 'â…¬' => 'L',
  15634. 'â…­' => 'C',
  15635. 'â…®' => 'D',
  15636. 'â…¯' => 'M',
  15637. 'â…°' => 'i',
  15638. 'â…±' => 'ii',
  15639. 'â…²' => 'iii',
  15640. 'â…³' => 'iv',
  15641. 'â…´' => 'v',
  15642. 'â…µ' => 'vi',
  15643. 'â…¶' => 'vii',
  15644. 'â…·' => 'viii',
  15645. 'â…¸' => 'ix',
  15646. 'â…¹' => 'x',
  15647. 'â…º' => 'xi',
  15648. 'â…»' => 'xii',
  15649. 'â…¼' => 'l',
  15650. 'â…½' => 'c',
  15651. 'â…¾' => 'd',
  15652. 'â…¿' => 'm',
  15653. '↉' => '0�3',
  15654. '∬' => '∫∫',
  15655. '∭' => '∫∫∫',
  15656. '∯' => '∮∮',
  15657. '∰' => '∮∮∮',
  15658. 'â‘ ' => '1',
  15659. 'â‘¡' => '2',
  15660. 'â‘¢' => '3',
  15661. 'â‘£' => '4',
  15662. '⑤' => '5',
  15663. 'â‘¥' => '6',
  15664. '⑦' => '7',
  15665. 'â‘§' => '8',
  15666. '⑨' => '9',
  15667. 'â‘©' => '10',
  15668. '⑪' => '11',
  15669. 'â‘«' => '12',
  15670. '⑬' => '13',
  15671. 'â‘­' => '14',
  15672. 'â‘®' => '15',
  15673. '⑯' => '16',
  15674. 'â‘°' => '17',
  15675. '⑱' => '18',
  15676. '⑲' => '19',
  15677. '⑳' => '20',
  15678. 'â‘´' => '(1)',
  15679. '⑵' => '(2)',
  15680. 'â‘¶' => '(3)',
  15681. 'â‘·' => '(4)',
  15682. '⑸' => '(5)',
  15683. '⑹' => '(6)',
  15684. '⑺' => '(7)',
  15685. 'â‘»' => '(8)',
  15686. '⑼' => '(9)',
  15687. '⑽' => '(10)',
  15688. '⑾' => '(11)',
  15689. 'â‘¿' => '(12)',
  15690. 'â’€' => '(13)',
  15691. 'â’�' => '(14)',
  15692. 'â’‚' => '(15)',
  15693. 'â’ƒ' => '(16)',
  15694. 'â’„' => '(17)',
  15695. 'â’…' => '(18)',
  15696. 'â’†' => '(19)',
  15697. 'â’‡' => '(20)',
  15698. 'â’ˆ' => '1.',
  15699. 'â’‰' => '2.',
  15700. 'â’Š' => '3.',
  15701. 'â’‹' => '4.',
  15702. '⒌' => '5.',
  15703. 'â’�' => '6.',
  15704. 'â’Ž' => '7.',
  15705. 'â’�' => '8.',
  15706. 'â’�' => '9.',
  15707. 'â’‘' => '10.',
  15708. 'â’’' => '11.',
  15709. 'â’“' => '12.',
  15710. 'â’”' => '13.',
  15711. 'â’•' => '14.',
  15712. 'â’–' => '15.',
  15713. 'â’—' => '16.',
  15714. 'â’˜' => '17.',
  15715. 'â’™' => '18.',
  15716. 'â’š' => '19.',
  15717. 'â’›' => '20.',
  15718. '⒜' => '(a)',
  15719. 'â’�' => '(b)',
  15720. 'â’ž' => '(c)',
  15721. 'â’Ÿ' => '(d)',
  15722. 'â’ ' => '(e)',
  15723. 'â’¡' => '(f)',
  15724. 'â’¢' => '(g)',
  15725. 'â’£' => '(h)',
  15726. 'â’¤' => '(i)',
  15727. 'â’¥' => '(j)',
  15728. 'â’¦' => '(k)',
  15729. 'â’§' => '(l)',
  15730. 'â’¨' => '(m)',
  15731. 'â’©' => '(n)',
  15732. 'â’ª' => '(o)',
  15733. 'â’«' => '(p)',
  15734. 'â’¬' => '(q)',
  15735. 'â’­' => '(r)',
  15736. 'â’®' => '(s)',
  15737. 'â’¯' => '(t)',
  15738. 'â’°' => '(u)',
  15739. 'â’±' => '(v)',
  15740. 'â’²' => '(w)',
  15741. 'â’³' => '(x)',
  15742. 'â’´' => '(y)',
  15743. 'â’µ' => '(z)',
  15744. 'â’¶' => 'A',
  15745. 'â’·' => 'B',
  15746. 'â’¸' => 'C',
  15747. 'â’¹' => 'D',
  15748. 'â’º' => 'E',
  15749. 'â’»' => 'F',
  15750. 'â’¼' => 'G',
  15751. 'â’½' => 'H',
  15752. 'â’¾' => 'I',
  15753. 'â’¿' => 'J',
  15754. 'â“€' => 'K',
  15755. '�' => 'L',
  15756. 'â“‚' => 'M',
  15757. 'Ⓝ' => 'N',
  15758. 'â“„' => 'O',
  15759. 'â“…' => 'P',
  15760. 'Ⓠ' => 'Q',
  15761. 'Ⓡ' => 'R',
  15762. 'Ⓢ' => 'S',
  15763. 'Ⓣ' => 'T',
  15764. 'Ⓤ' => 'U',
  15765. 'â“‹' => 'V',
  15766. 'Ⓦ' => 'W',
  15767. '�' => 'X',
  15768. 'Ⓨ' => 'Y',
  15769. '�' => 'Z',
  15770. '�' => 'a',
  15771. 'â“‘' => 'b',
  15772. 'â“’' => 'c',
  15773. 'â““' => 'd',
  15774. 'â“”' => 'e',
  15775. 'â“•' => 'f',
  15776. 'â“–' => 'g',
  15777. 'â“—' => 'h',
  15778. 'ⓘ' => 'i',
  15779. 'â“™' => 'j',
  15780. 'ⓚ' => 'k',
  15781. 'â“›' => 'l',
  15782. 'ⓜ' => 'm',
  15783. '�' => 'n',
  15784. 'ⓞ' => 'o',
  15785. 'ⓟ' => 'p',
  15786. 'â“ ' => 'q',
  15787. 'â“¡' => 'r',
  15788. 'â“¢' => 's',
  15789. 'â“£' => 't',
  15790. 'ⓤ' => 'u',
  15791. 'â“¥' => 'v',
  15792. 'ⓦ' => 'w',
  15793. 'â“§' => 'x',
  15794. 'ⓨ' => 'y',
  15795. 'â“©' => 'z',
  15796. '⓪' => '0',
  15797. '⨌' => '∫∫∫∫',
  15798. 'â©´' => '::=',
  15799. '⩵' => '==',
  15800. 'â©¶' => '===',
  15801. 'â±¼' => 'j',
  15802. 'â±½' => 'V',
  15803. 'ⵯ' => 'ⵡ',
  15804. '⺟' => '�',
  15805. '⻳' => '龟',
  15806. '⼀' => '一',
  15807. '�' => '丨',
  15808. '⼂' => '丶',
  15809. '⼃' => '丿',
  15810. '⼄' => '乙',
  15811. '⼅' => '亅',
  15812. '⼆' => '二',
  15813. '⼇' => '亠',
  15814. '⼈' => '人',
  15815. '⼉' => '儿',
  15816. '⼊' => '入',
  15817. '⼋' => '八',
  15818. '⼌' => '冂',
  15819. '�' => '冖',
  15820. '⼎' => '冫',
  15821. '�' => '几',
  15822. '�' => '凵',
  15823. '⼑' => '刀',
  15824. '⼒' => '力',
  15825. '⼓' => '勹',
  15826. '⼔' => '匕',
  15827. '⼕' => '匚',
  15828. '⼖' => '匸',
  15829. '⼗' => '�',
  15830. '⼘' => '�',
  15831. '⼙' => '�',
  15832. '⼚' => '厂',
  15833. '⼛' => '厶',
  15834. '⼜' => '�',
  15835. '�' => '�',
  15836. '⼞' => '囗',
  15837. '⼟' => '土',
  15838. '⼠' => '士',
  15839. '⼡' => '夂',
  15840. '⼢' => '夊',
  15841. '⼣' => '夕',
  15842. '⼤' => '大',
  15843. '⼥' => '女',
  15844. '⼦' => '�',
  15845. '⼧' => '宀',
  15846. '⼨' => '寸',
  15847. '⼩' => '�',
  15848. '⼪' => '尢',
  15849. '⼫' => '尸',
  15850. '⼬' => '屮',
  15851. 'â¼­' => 'å±±',
  15852. 'â¼®' => 'å·›',
  15853. '⼯' => '工',
  15854. 'â¼°' => 'å·±',
  15855. 'â¼±' => 'å·¾',
  15856. 'â¼²' => 'å¹²',
  15857. '⼳' => '幺',
  15858. '⼴' => '广',
  15859. 'â¼µ' => 'å»´',
  15860. '⼶' => '廾',
  15861. '⼷' => '弋',
  15862. '⼸' => '弓',
  15863. '⼹' => '�',
  15864. '⼺' => '彡',
  15865. 'â¼»' => 'å½³',
  15866. '⼼' => '心',
  15867. '⼽' => '戈',
  15868. '⼾' => '戶',
  15869. '⼿' => '手',
  15870. '⽀' => '支',
  15871. '�' => '攴',
  15872. '⽂' => '文',
  15873. '⽃' => '斗',
  15874. '⽄' => '斤',
  15875. 'â½…' => 'æ–¹',
  15876. '⽆' => '无',
  15877. '⽇' => '日',
  15878. '⽈' => '曰',
  15879. '⽉' => '月',
  15880. '⽊' => '木',
  15881. '⽋' => '欠',
  15882. '⽌' => '止',
  15883. '�' => '歹',
  15884. '⽎' => '殳',
  15885. '�' => '毋',
  15886. '�' => '比',
  15887. '⽑' => '毛',
  15888. 'â½’' => 'æ°�',
  15889. '⽓' => '气',
  15890. 'â½”' => 'æ°´',
  15891. '⽕' => '�',
  15892. '⽖' => '爪',
  15893. '⽗' => '父',
  15894. '⽘' => '爻',
  15895. '⽙' => '爿',
  15896. '⽚' => '片',
  15897. '⽛' => '牙',
  15898. '⽜' => '牛',
  15899. '�' => '犬',
  15900. '⽞' => '玄',
  15901. '⽟' => '玉',
  15902. '⽠' => '瓜',
  15903. '⽡' => '瓦',
  15904. '⽢' => '甘',
  15905. '⽣' => '生',
  15906. '⽤' => '用',
  15907. 'â½¥' => 'ç”°',
  15908. '⽦' => '疋',
  15909. 'â½§' => 'ç–’',
  15910. '⽨' => '癶',
  15911. '⽩' => '白',
  15912. '⽪' => '皮',
  15913. '⽫' => '皿',
  15914. '⽬' => '目',
  15915. '⽭' => '矛',
  15916. '⽮' => '矢',
  15917. '⽯' => '石',
  15918. '⽰' => '示',
  15919. '⽱' => '禸',
  15920. '⽲' => '禾',
  15921. 'â½³' => 'ç©´',
  15922. 'â½´' => 'ç«‹',
  15923. '⽵' => '竹',
  15924. 'â½¶' => 'ç±³',
  15925. '⽷' => '糸',
  15926. '⽸' => '缶',
  15927. '⽹' => '网',
  15928. '⽺' => '羊',
  15929. 'â½»' => 'ç¾½',
  15930. '⽼' => '�',
  15931. '⽽' => '而',
  15932. '⽾' => '耒',
  15933. '⽿' => '耳',
  15934. '⾀' => '�',
  15935. '�' => '肉',
  15936. '⾂' => '臣',
  15937. '⾃' => '自',
  15938. '⾄' => '至',
  15939. '⾅' => '臼',
  15940. '⾆' => '舌',
  15941. '⾇' => '舛',
  15942. '⾈' => '舟',
  15943. '⾉' => '艮',
  15944. '⾊' => '色',
  15945. '⾋' => '艸',
  15946. '⾌' => '�',
  15947. '�' => '虫',
  15948. '⾎' => '血',
  15949. '�' => '行',
  15950. '�' => '衣',
  15951. '⾑' => '襾',
  15952. '⾒' => '見',
  15953. '⾓' => '角',
  15954. '⾔' => '言',
  15955. '⾕' => '谷',
  15956. '⾖' => '豆',
  15957. '⾗' => '豕',
  15958. '⾘' => '豸',
  15959. '⾙' => '�',
  15960. '⾚' => '赤',
  15961. 'â¾›' => 'èµ°',
  15962. '⾜' => '足',
  15963. '�' => '身',
  15964. '⾞' => '車',
  15965. '⾟' => '辛',
  15966. 'â¾ ' => 'è¾°',
  15967. '⾡' => '辵',
  15968. 'â¾¢' => 'é‚‘',
  15969. 'â¾£' => 'é…‰',
  15970. '⾤' => '釆',
  15971. '⾥' => '里',
  15972. '⾦' => '金',
  15973. 'â¾§' => 'é•·',
  15974. '⾨' => '門',
  15975. '⾩' => '阜',
  15976. '⾪' => '隶',
  15977. '⾫' => '隹',
  15978. '⾬' => '雨',
  15979. '⾭' => '�',
  15980. '⾮' => '�',
  15981. '⾯' => '�',
  15982. '⾰' => '�',
  15983. '⾱' => '韋',
  15984. '⾲' => '韭',
  15985. '⾳' => '音',
  15986. 'â¾´' => 'é �',
  15987. '⾵' => '風',
  15988. '⾶' => '飛',
  15989. '⾷' => '食',
  15990. '⾸' => '首',
  15991. '⾹' => '香',
  15992. '⾺' => '馬',
  15993. '⾻' => '骨',
  15994. '⾼' => '高',
  15995. '⾽' => '髟',
  15996. '⾾' => '鬥',
  15997. '⾿' => '鬯',
  15998. '⿀' => '鬲',
  15999. '�' => '鬼',
  16000. 'â¿‚' => 'é­š',
  16001. '⿃' => '鳥',
  16002. 'â¿„' => 'é¹µ',
  16003. '⿅' => '鹿',
  16004. '⿆' => '麥',
  16005. '⿇' => '麻',
  16006. '⿈' => '黃',
  16007. '⿉' => '�',
  16008. '⿊' => '黑',
  16009. '⿋' => '黹',
  16010. '⿌' => '黽',
  16011. '�' => '鼎',
  16012. '⿎' => '鼓',
  16013. '�' => '鼠',
  16014. '�' => '鼻',
  16015. '⿑' => '齊',
  16016. 'â¿’' => 'é½’',
  16017. '⿓' => '�',
  16018. '⿔' => '龜',
  16019. 'â¿•' => 'é¾ ',
  16020. ' ' => ' ',
  16021. '〶' => '〒',
  16022. '〸' => '�',
  16023. '〹' => '�',
  16024. '〺' => '�',
  16025. 'ã‚›' => ' ã‚™',
  16026. '゜' => ' ゚',
  16027. 'ゟ' => 'より',
  16028. 'ヿ' => 'コト',
  16029. 'ㄱ' => 'ᄀ',
  16030. 'ㄲ' => '�',
  16031. 'ㄳ' => 'ᆪ',
  16032. 'ã„´' => 'á„‚',
  16033. 'ㄵ' => 'ᆬ',
  16034. 'ㄶ' => 'ᆭ',
  16035. 'ㄷ' => 'ᄃ',
  16036. 'ㄸ' => 'ᄄ',
  16037. 'ㄹ' => 'ᄅ',
  16038. 'ㄺ' => 'ᆰ',
  16039. 'ㄻ' => 'ᆱ',
  16040. 'ㄼ' => 'ᆲ',
  16041. 'ㄽ' => 'ᆳ',
  16042. 'ㄾ' => 'ᆴ',
  16043. 'ㄿ' => 'ᆵ',
  16044. 'ㅀ' => 'ᄚ',
  16045. '�' => 'ᄆ',
  16046. 'ㅂ' => 'ᄇ',
  16047. 'ㅃ' => 'ᄈ',
  16048. 'ã…„' => 'á„¡',
  16049. 'ㅅ' => 'ᄉ',
  16050. 'ㅆ' => 'ᄊ',
  16051. 'ã…‡' => 'á„‹',
  16052. 'ㅈ' => 'ᄌ',
  16053. 'ㅉ' => '�',
  16054. 'ㅊ' => 'ᄎ',
  16055. 'ㅋ' => '�',
  16056. 'ㅌ' => '�',
  16057. 'ã…�' => 'á„‘',
  16058. 'ã…Ž' => 'á„’',
  16059. 'ã…�' => 'á…¡',
  16060. 'ã…�' => 'á…¢',
  16061. 'ã…‘' => 'á…£',
  16062. 'ã…’' => 'á…¤',
  16063. 'ã…“' => 'á…¥',
  16064. 'ã…”' => 'á…¦',
  16065. 'ã…•' => 'á…§',
  16066. 'ã…–' => 'á…¨',
  16067. 'ã…—' => 'á…©',
  16068. 'ã…˜' => 'á…ª',
  16069. 'ã…™' => 'á…«',
  16070. 'ã…š' => 'á…¬',
  16071. 'ã…›' => 'á…­',
  16072. 'ㅜ' => 'ᅮ',
  16073. 'ã…�' => 'á…¯',
  16074. 'ã…ž' => 'á…°',
  16075. 'ã…Ÿ' => 'á…±',
  16076. 'ã… ' => 'á…²',
  16077. 'ã…¡' => 'á…³',
  16078. 'ã…¢' => 'á…´',
  16079. 'ã…£' => 'á…µ',
  16080. 'ã…¤' => 'á… ',
  16081. 'ã…¥' => 'á„”',
  16082. 'ã…¦' => 'á„•',
  16083. 'ㅧ' => 'ᇇ',
  16084. 'ㅨ' => 'ᇈ',
  16085. 'ㅩ' => 'ᇌ',
  16086. 'ㅪ' => 'ᇎ',
  16087. 'ㅫ' => 'ᇓ',
  16088. 'ㅬ' => 'ᇗ',
  16089. 'ㅭ' => 'ᇙ',
  16090. 'ㅮ' => 'ᄜ',
  16091. 'ㅯ' => '�',
  16092. 'ㅰ' => 'ᇟ',
  16093. 'ㅱ' => '�',
  16094. 'ㅲ' => 'ᄞ',
  16095. 'ã…³' => 'á„ ',
  16096. 'ã…´' => 'á„¢',
  16097. 'ã…µ' => 'á„£',
  16098. 'ã…¶' => 'á„§',
  16099. 'ã…·' => 'á„©',
  16100. 'ã…¸' => 'á„«',
  16101. 'ㅹ' => 'ᄬ',
  16102. 'ã…º' => 'á„­',
  16103. 'ã…»' => 'á„®',
  16104. 'ㅼ' => 'ᄯ',
  16105. 'ㅽ' => 'ᄲ',
  16106. 'ã…¾' => 'á„¶',
  16107. 'ã…¿' => 'á…€',
  16108. 'ㆀ' => 'ᅇ',
  16109. '�' => 'ᅌ',
  16110. 'ㆂ' => 'ᇱ',
  16111. 'ㆃ' => 'ᇲ',
  16112. 'ㆄ' => 'ᅗ',
  16113. 'ㆅ' => 'ᅘ',
  16114. 'ㆆ' => 'ᅙ',
  16115. 'ㆇ' => 'ᆄ',
  16116. 'ㆈ' => 'ᆅ',
  16117. 'ㆉ' => 'ᆈ',
  16118. 'ㆊ' => 'ᆑ',
  16119. 'ㆋ' => 'ᆒ',
  16120. 'ㆌ' => 'ᆔ',
  16121. '�' => 'ᆞ',
  16122. 'ㆎ' => 'ᆡ',
  16123. '㆒' => '一',
  16124. '㆓' => '二',
  16125. '㆔' => '三',
  16126. '㆕' => '四',
  16127. '㆖' => '上',
  16128. '㆗' => '中',
  16129. '㆘' => '下',
  16130. '㆙' => '甲',
  16131. '㆚' => '乙',
  16132. '㆛' => '丙',
  16133. '㆜' => '�',
  16134. '�' => '天',
  16135. '㆞' => '地',
  16136. '㆟' => '人',
  16137. '㈀' => '(ᄀ)',
  16138. '�' => '(ᄂ)',
  16139. '㈂' => '(ᄃ)',
  16140. '㈃' => '(ᄅ)',
  16141. '㈄' => '(ᄆ)',
  16142. '㈅' => '(ᄇ)',
  16143. '㈆' => '(ᄉ)',
  16144. '㈇' => '(ᄋ)',
  16145. '㈈' => '(ᄌ)',
  16146. '㈉' => '(ᄎ)',
  16147. '㈊' => '(�)',
  16148. '㈋' => '(�)',
  16149. '㈌' => '(ᄑ)',
  16150. '�' => '(ᄒ)',
  16151. '㈎' => '(가)',
  16152. '�' => '(나)',
  16153. '�' => '(다)',
  16154. '㈑' => '(라)',
  16155. '㈒' => '(마)',
  16156. '㈓' => '(바)',
  16157. '㈔' => '(사)',
  16158. '㈕' => '(아)',
  16159. '㈖' => '(자)',
  16160. '㈗' => '(차)',
  16161. '㈘' => '(�ᅡ)',
  16162. '㈙' => '(�ᅡ)',
  16163. '㈚' => '(파)',
  16164. '㈛' => '(하)',
  16165. '㈜' => '(주)',
  16166. '�' => '(오전)',
  16167. '㈞' => '(오후)',
  16168. '㈠' => '(一)',
  16169. '㈡' => '(二)',
  16170. '㈢' => '(三)',
  16171. '㈣' => '(四)',
  16172. '㈤' => '(五)',
  16173. '㈥' => '(六)',
  16174. '㈦' => '(七)',
  16175. '㈧' => '(八)',
  16176. '㈨' => '(�)',
  16177. '㈩' => '(�)',
  16178. '㈪' => '(月)',
  16179. '㈫' => '(�)',
  16180. '㈬' => '(水)',
  16181. '㈭' => '(木)',
  16182. '㈮' => '(金)',
  16183. '㈯' => '(土)',
  16184. '㈰' => '(日)',
  16185. '㈱' => '(株)',
  16186. '㈲' => '(有)',
  16187. '㈳' => '(社)',
  16188. '㈴' => '(�)',
  16189. '㈵' => '(特)',
  16190. '㈶' => '(財)',
  16191. '㈷' => '(�)',
  16192. '㈸' => '(労)',
  16193. '㈹' => '(代)',
  16194. '㈺' => '(呼)',
  16195. '㈻' => '(学)',
  16196. '㈼' => '(監)',
  16197. '㈽' => '(�)',
  16198. '㈾' => '(資)',
  16199. '㈿' => '(�)',
  16200. '㉀' => '(祭)',
  16201. '�' => '(休)',
  16202. '㉂' => '(自)',
  16203. '㉃' => '(至)',
  16204. '㉄' => '�',
  16205. '㉅' => '幼',
  16206. '㉆' => '文',
  16207. '㉇' => '�',
  16208. '�' => 'PTE',
  16209. '㉑' => '21',
  16210. '㉒' => '22',
  16211. '㉓' => '23',
  16212. '㉔' => '24',
  16213. '㉕' => '25',
  16214. '㉖' => '26',
  16215. '㉗' => '27',
  16216. '㉘' => '28',
  16217. '㉙' => '29',
  16218. '㉚' => '30',
  16219. '㉛' => '31',
  16220. '㉜' => '32',
  16221. '�' => '33',
  16222. '㉞' => '34',
  16223. '㉟' => '35',
  16224. '㉠' => 'ᄀ',
  16225. '㉡' => 'ᄂ',
  16226. '㉢' => 'ᄃ',
  16227. '㉣' => 'ᄅ',
  16228. '㉤' => 'ᄆ',
  16229. '㉥' => 'ᄇ',
  16230. '㉦' => 'ᄉ',
  16231. '㉧' => 'ᄋ',
  16232. '㉨' => 'ᄌ',
  16233. '㉩' => 'ᄎ',
  16234. '㉪' => '�',
  16235. '㉫' => '�',
  16236. '㉬' => 'ᄑ',
  16237. '㉭' => 'ᄒ',
  16238. '㉮' => '가',
  16239. '㉯' => '나',
  16240. '㉰' => '다',
  16241. '㉱' => '라',
  16242. '㉲' => '마',
  16243. '㉳' => '바',
  16244. '㉴' => '사',
  16245. '㉵' => '아',
  16246. '㉶' => '자',
  16247. '㉷' => '차',
  16248. '㉸' => '�ᅡ',
  16249. '㉹' => '�ᅡ',
  16250. '㉺' => '파',
  16251. '㉻' => '하',
  16252. '㉼' => '참고',
  16253. '㉽' => '주의',
  16254. '㉾' => '우',
  16255. '㊀' => '一',
  16256. '�' => '二',
  16257. '㊂' => '三',
  16258. '㊃' => '四',
  16259. '㊄' => '五',
  16260. '㊅' => '六',
  16261. '㊆' => '七',
  16262. '㊇' => '八',
  16263. '㊈' => '�',
  16264. '㊉' => '�',
  16265. '㊊' => '月',
  16266. '㊋' => '�',
  16267. '㊌' => '水',
  16268. '�' => '木',
  16269. '㊎' => '金',
  16270. '�' => '土',
  16271. '�' => '日',
  16272. '㊑' => '株',
  16273. '㊒' => '有',
  16274. '㊓' => '社',
  16275. '㊔' => '�',
  16276. '㊕' => '特',
  16277. '㊖' => '財',
  16278. '㊗' => '�',
  16279. '㊘' => '労',
  16280. '㊙' => '秘',
  16281. '㊚' => '男',
  16282. '㊛' => '女',
  16283. '㊜' => '�',
  16284. '�' => '優',
  16285. '㊞' => '�',
  16286. '㊟' => '注',
  16287. '㊠' => '項',
  16288. '㊡' => '休',
  16289. '㊢' => '写',
  16290. '㊣' => '正',
  16291. '㊤' => '上',
  16292. '㊥' => '中',
  16293. '㊦' => '下',
  16294. '㊧' => '左',
  16295. '㊨' => '�',
  16296. '㊩' => '医',
  16297. '㊪' => '宗',
  16298. '㊫' => '学',
  16299. '㊬' => '監',
  16300. '㊭' => '�',
  16301. '㊮' => '資',
  16302. '㊯' => '�',
  16303. '㊰' => '夜',
  16304. '㊱' => '36',
  16305. '㊲' => '37',
  16306. '㊳' => '38',
  16307. '㊴' => '39',
  16308. '㊵' => '40',
  16309. '㊶' => '41',
  16310. '㊷' => '42',
  16311. '㊸' => '43',
  16312. '㊹' => '44',
  16313. '㊺' => '45',
  16314. '㊻' => '46',
  16315. '㊼' => '47',
  16316. '㊽' => '48',
  16317. '㊾' => '49',
  16318. '㊿' => '50',
  16319. '㋀' => '1月',
  16320. '�' => '2月',
  16321. '㋂' => '3月',
  16322. '㋃' => '4月',
  16323. '㋄' => '5月',
  16324. '㋅' => '6月',
  16325. '㋆' => '7月',
  16326. '㋇' => '8月',
  16327. '㋈' => '9月',
  16328. '㋉' => '10月',
  16329. '㋊' => '11月',
  16330. '㋋' => '12月',
  16331. '㋌' => 'Hg',
  16332. '�' => 'erg',
  16333. '㋎' => 'eV',
  16334. '�' => 'LTD',
  16335. '�' => 'ア',
  16336. '㋑' => 'イ',
  16337. '㋒' => 'ウ',
  16338. '㋓' => 'エ',
  16339. '㋔' => 'オ',
  16340. 'ã‹•' => 'ã‚«',
  16341. 'ã‹–' => 'ã‚­',
  16342. '㋗' => 'ク',
  16343. '㋘' => 'ケ',
  16344. '㋙' => 'コ',
  16345. '㋚' => 'サ',
  16346. 'ã‹›' => 'ã‚·',
  16347. '㋜' => 'ス',
  16348. '�' => 'セ',
  16349. '㋞' => 'ソ',
  16350. '㋟' => 'タ',
  16351. '㋠' => '�',
  16352. '㋡' => 'ツ',
  16353. '㋢' => 'テ',
  16354. '㋣' => 'ト',
  16355. '㋤' => 'ナ',
  16356. '㋥' => 'ニ',
  16357. '㋦' => 'ヌ',
  16358. '㋧' => '�',
  16359. '㋨' => 'ノ',
  16360. '㋩' => '�',
  16361. '㋪' => 'ヒ',
  16362. '㋫' => 'フ',
  16363. '㋬' => 'ヘ',
  16364. '㋭' => 'ホ',
  16365. '㋮' => 'マ',
  16366. '㋯' => 'ミ',
  16367. '㋰' => 'ム',
  16368. '㋱' => 'メ',
  16369. '㋲' => 'モ',
  16370. '㋳' => 'ヤ',
  16371. '㋴' => 'ユ',
  16372. '㋵' => 'ヨ',
  16373. '㋶' => 'ラ',
  16374. '㋷' => 'リ',
  16375. '㋸' => 'ル',
  16376. '㋹' => 'レ',
  16377. '㋺' => 'ロ',
  16378. '㋻' => 'ワ',
  16379. '㋼' => 'ヰ',
  16380. '㋽' => 'ヱ',
  16381. '㋾' => 'ヲ',
  16382. '㋿' => '令和',
  16383. '㌀' => 'ア�゚ート',
  16384. '�' => 'アルファ',
  16385. '㌂' => 'アンペア',
  16386. '㌃' => 'アール',
  16387. '㌄' => 'イニング',
  16388. '㌅' => 'イン�',
  16389. '㌆' => 'ウォン',
  16390. '㌇' => 'エスクード',
  16391. '㌈' => 'エーカー',
  16392. '㌉' => 'オンス',
  16393. '㌊' => 'オーム',
  16394. '㌋' => 'カイリ',
  16395. '㌌' => 'カラット',
  16396. '�' => 'カロリー',
  16397. '㌎' => 'ガロン',
  16398. '�' => 'ガンマ',
  16399. '�' => 'ギガ',
  16400. '㌑' => 'ギニー',
  16401. '㌒' => 'キュリー',
  16402. '㌓' => 'ギルダー',
  16403. '㌔' => 'キロ',
  16404. '㌕' => 'キログラム',
  16405. '㌖' => 'キロメートル',
  16406. '㌗' => 'キロワット',
  16407. '㌘' => 'グラム',
  16408. '㌙' => 'グラムトン',
  16409. '㌚' => 'クルゼイロ',
  16410. '㌛' => 'クロー�',
  16411. '㌜' => 'ケース',
  16412. '�' => 'コルナ',
  16413. '㌞' => 'コーポ',
  16414. '㌟' => 'サイクル',
  16415. '㌠' => 'サン�ーム',
  16416. '㌡' => 'シリング',
  16417. '㌢' => 'セン�',
  16418. '㌣' => 'セント',
  16419. '㌤' => 'ダース',
  16420. '㌥' => 'デシ',
  16421. '㌦' => 'ドル',
  16422. '㌧' => 'トン',
  16423. '㌨' => 'ナノ',
  16424. '㌩' => 'ノット',
  16425. '㌪' => '�イツ',
  16426. '㌫' => '�゚ーセント',
  16427. '㌬' => '�゚ーツ',
  16428. '㌭' => '�゙ーレル',
  16429. '㌮' => 'ピアストル',
  16430. '㌯' => 'ピクル',
  16431. '㌰' => 'ピコ',
  16432. '㌱' => 'ビル',
  16433. '㌲' => 'ファラッド',
  16434. '㌳' => 'フィート',
  16435. '㌴' => 'ブッシェル',
  16436. '㌵' => 'フラン',
  16437. '㌶' => 'ヘクタール',
  16438. '㌷' => 'ペソ',
  16439. '㌸' => 'ペニヒ',
  16440. '㌹' => 'ヘルツ',
  16441. '㌺' => 'ペンス',
  16442. '㌻' => 'ページ',
  16443. '㌼' => 'ベータ',
  16444. '㌽' => 'ポイント',
  16445. '㌾' => 'ボルト',
  16446. '㌿' => 'ホン',
  16447. '�' => 'ポンド',
  16448. '�' => 'ホール',
  16449. '�' => 'ホーン',
  16450. '�' => 'マイクロ',
  16451. '�' => 'マイル',
  16452. '�' => 'マッ�',
  16453. '�' => 'マルク',
  16454. '�' => 'マンション',
  16455. '�' => 'ミクロン',
  16456. '�' => 'ミリ',
  16457. '�' => 'ミリ�゙ール',
  16458. '�' => 'メガ',
  16459. '�' => 'メガトン',
  16460. '�' => 'メートル',
  16461. '�' => 'ヤード',
  16462. '�' => 'ヤール',
  16463. '�' => 'ユアン',
  16464. '�' => 'リットル',
  16465. '�' => 'リラ',
  16466. '�' => 'ルピー',
  16467. '�' => 'ルーブル',
  16468. '�' => 'レム',
  16469. '�' => 'レントゲン',
  16470. '�' => 'ワット',
  16471. '�' => '0点',
  16472. '�' => '1点',
  16473. '�' => '2点',
  16474. '�' => '3点',
  16475. '�' => '4点',
  16476. '�' => '5点',
  16477. '�' => '6点',
  16478. '�' => '7点',
  16479. '�' => '8点',
  16480. '�' => '9点',
  16481. '�' => '10点',
  16482. '�' => '11点',
  16483. '�' => '12点',
  16484. '�' => '13点',
  16485. '�' => '14点',
  16486. '�' => '15点',
  16487. '�' => '16点',
  16488. '�' => '17点',
  16489. '�' => '18点',
  16490. '�' => '19点',
  16491. '�' => '20点',
  16492. '�' => '21点',
  16493. '�' => '22点',
  16494. '�' => '23点',
  16495. '�' => '24点',
  16496. '�' => 'hPa',
  16497. '�' => 'da',
  16498. '�' => 'AU',
  16499. '�' => 'bar',
  16500. '�' => 'oV',
  16501. '�' => 'pc',
  16502. '�' => 'dm',
  16503. '�' => 'dm2',
  16504. '�' => 'dm3',
  16505. '�' => 'IU',
  16506. '�' => '平�',
  16507. '�' => '昭和',
  16508. '�' => '大正',
  16509. '�' => '明治',
  16510. '�' => '株�会社',
  16511. '㎀' => 'pA',
  16512. '�' => 'nA',
  16513. '㎂' => 'μA',
  16514. '㎃' => 'mA',
  16515. '㎄' => 'kA',
  16516. '㎅' => 'KB',
  16517. '㎆' => 'MB',
  16518. '㎇' => 'GB',
  16519. '㎈' => 'cal',
  16520. '㎉' => 'kcal',
  16521. '㎊' => 'pF',
  16522. '㎋' => 'nF',
  16523. '㎌' => 'μF',
  16524. '�' => 'μg',
  16525. '㎎' => 'mg',
  16526. '�' => 'kg',
  16527. '�' => 'Hz',
  16528. '㎑' => 'kHz',
  16529. '㎒' => 'MHz',
  16530. '㎓' => 'GHz',
  16531. '㎔' => 'THz',
  16532. '㎕' => 'μl',
  16533. '㎖' => 'ml',
  16534. '㎗' => 'dl',
  16535. '㎘' => 'kl',
  16536. '㎙' => 'fm',
  16537. '㎚' => 'nm',
  16538. '㎛' => 'μm',
  16539. '㎜' => 'mm',
  16540. '�' => 'cm',
  16541. '㎞' => 'km',
  16542. '㎟' => 'mm2',
  16543. '㎠' => 'cm2',
  16544. '㎡' => 'm2',
  16545. '㎢' => 'km2',
  16546. '㎣' => 'mm3',
  16547. '㎤' => 'cm3',
  16548. '㎥' => 'm3',
  16549. '㎦' => 'km3',
  16550. '㎧' => 'm∕s',
  16551. '㎨' => 'm∕s2',
  16552. '㎩' => 'Pa',
  16553. '㎪' => 'kPa',
  16554. '㎫' => 'MPa',
  16555. '㎬' => 'GPa',
  16556. '㎭' => 'rad',
  16557. '㎮' => 'rad∕s',
  16558. '㎯' => 'rad∕s2',
  16559. '㎰' => 'ps',
  16560. '㎱' => 'ns',
  16561. '㎲' => 'μs',
  16562. '㎳' => 'ms',
  16563. '㎴' => 'pV',
  16564. '㎵' => 'nV',
  16565. '㎶' => 'μV',
  16566. '㎷' => 'mV',
  16567. '㎸' => 'kV',
  16568. '㎹' => 'MV',
  16569. '㎺' => 'pW',
  16570. '㎻' => 'nW',
  16571. '㎼' => 'μW',
  16572. '㎽' => 'mW',
  16573. '㎾' => 'kW',
  16574. '㎿' => 'MW',
  16575. '�' => 'kΩ',
  16576. '�' => 'MΩ',
  16577. '�' => 'a.m.',
  16578. '�' => 'Bq',
  16579. '�' => 'cc',
  16580. '�' => 'cd',
  16581. '�' => 'C∕kg',
  16582. '�' => 'Co.',
  16583. '�' => 'dB',
  16584. '�' => 'Gy',
  16585. '�' => 'ha',
  16586. '�' => 'HP',
  16587. '�' => 'in',
  16588. '�' => 'KK',
  16589. '�' => 'KM',
  16590. '�' => 'kt',
  16591. '�' => 'lm',
  16592. '�' => 'ln',
  16593. '�' => 'log',
  16594. '�' => 'lx',
  16595. '�' => 'mb',
  16596. '�' => 'mil',
  16597. '�' => 'mol',
  16598. '�' => 'PH',
  16599. '�' => 'p.m.',
  16600. '�' => 'PPM',
  16601. '�' => 'PR',
  16602. '�' => 'sr',
  16603. '�' => 'Sv',
  16604. '�' => 'Wb',
  16605. '�' => 'V∕m',
  16606. '�' => 'A∕m',
  16607. '�' => '1日',
  16608. '�' => '2日',
  16609. '�' => '3日',
  16610. '�' => '4日',
  16611. '�' => '5日',
  16612. '�' => '6日',
  16613. '�' => '7日',
  16614. '�' => '8日',
  16615. '�' => '9日',
  16616. '�' => '10日',
  16617. '�' => '11日',
  16618. '�' => '12日',
  16619. '�' => '13日',
  16620. '�' => '14日',
  16621. '�' => '15日',
  16622. '�' => '16日',
  16623. '�' => '17日',
  16624. '�' => '18日',
  16625. '�' => '19日',
  16626. '�' => '20日',
  16627. '�' => '21日',
  16628. '�' => '22日',
  16629. '�' => '23日',
  16630. '�' => '24日',
  16631. '�' => '25日',
  16632. '�' => '26日',
  16633. '�' => '27日',
  16634. '�' => '28日',
  16635. '�' => '29日',
  16636. '�' => '30日',
  16637. '�' => '31日',
  16638. '�' => 'gal',
  16639. 'ꚜ' => 'ъ',
  16640. '�' => 'ь',
  16641. '�' => '�',
  16642. 'ꟸ' => 'Ħ',
  16643. 'ꟹ' => 'œ',
  16644. 'ꭜ' => 'ꜧ',
  16645. '�' => 'ꬷ',
  16646. 'ê­ž' => 'É«',
  16647. 'ê­Ÿ' => 'ê­’',
  16648. 'ꭩ' => '�',
  16649. 'ff' => 'ff',
  16650. '�' => 'fi',
  16651. 'fl' => 'fl',
  16652. 'ffi' => 'ffi',
  16653. 'ffl' => 'ffl',
  16654. 'ſt' => 'st',
  16655. 'st' => 'st',
  16656. 'ﬓ' => 'մն',
  16657. 'ﬔ' => 'մե',
  16658. 'ﬕ' => 'մի',
  16659. 'ﬖ' => 'վն',
  16660. 'ﬗ' => 'մխ',
  16661. 'ﬠ' => 'ע',
  16662. 'ﬡ' => '�',
  16663. 'ﬢ' => 'ד',
  16664. 'ﬣ' => 'ה',
  16665. 'ﬤ' => 'כ',
  16666. 'ﬥ' => 'ל',
  16667. 'ﬦ' => '�',
  16668. 'ﬧ' => 'ר',
  16669. 'ﬨ' => 'ת',
  16670. '﬩' => '+',
  16671. '�' => '�ל',
  16672. 'ï­�' => 'Ù±',
  16673. 'ï­‘' => 'Ù±',
  16674. 'ï­’' => 'Ù»',
  16675. 'ï­“' => 'Ù»',
  16676. 'ï­”' => 'Ù»',
  16677. 'ï­•' => 'Ù»',
  16678. 'ï­–' => 'Ù¾',
  16679. 'ï­—' => 'Ù¾',
  16680. 'ï­˜' => 'Ù¾',
  16681. 'ï­™' => 'Ù¾',
  16682. 'ï­š' => 'Ú€',
  16683. 'ï­›' => 'Ú€',
  16684. 'ﭜ' => 'ڀ',
  16685. 'ï­�' => 'Ú€',
  16686. 'ï­ž' => 'Ùº',
  16687. 'ï­Ÿ' => 'Ùº',
  16688. 'ï­ ' => 'Ùº',
  16689. 'ï­¡' => 'Ùº',
  16690. 'ï­¢' => 'Ù¿',
  16691. 'ï­£' => 'Ù¿',
  16692. 'ï­¤' => 'Ù¿',
  16693. 'ï­¥' => 'Ù¿',
  16694. 'ï­¦' => 'Ù¹',
  16695. 'ï­§' => 'Ù¹',
  16696. 'ï­¨' => 'Ù¹',
  16697. 'ï­©' => 'Ù¹',
  16698. 'ï­ª' => 'Ú¤',
  16699. 'ï­«' => 'Ú¤',
  16700. 'ï­¬' => 'Ú¤',
  16701. 'ï­­' => 'Ú¤',
  16702. 'ï­®' => 'Ú¦',
  16703. 'ï­¯' => 'Ú¦',
  16704. 'ï­°' => 'Ú¦',
  16705. 'ï­±' => 'Ú¦',
  16706. 'ï­²' => 'Ú„',
  16707. 'ï­³' => 'Ú„',
  16708. 'ï­´' => 'Ú„',
  16709. 'ï­µ' => 'Ú„',
  16710. 'ï­¶' => 'Úƒ',
  16711. 'ï­·' => 'Úƒ',
  16712. 'ï­¸' => 'Úƒ',
  16713. 'ï­¹' => 'Úƒ',
  16714. 'ï­º' => 'Ú†',
  16715. 'ï­»' => 'Ú†',
  16716. 'ï­¼' => 'Ú†',
  16717. 'ï­½' => 'Ú†',
  16718. 'ï­¾' => 'Ú‡',
  16719. 'ï­¿' => 'Ú‡',
  16720. 'ﮀ' => 'ڇ',
  16721. '�' => 'ڇ',
  16722. 'ﮂ' => '�',
  16723. 'ﮃ' => '�',
  16724. 'ﮄ' => 'ڌ',
  16725. 'ﮅ' => 'ڌ',
  16726. 'ﮆ' => 'ڎ',
  16727. 'ﮇ' => 'ڎ',
  16728. 'ﮈ' => 'ڈ',
  16729. 'ﮉ' => 'ڈ',
  16730. 'ﮊ' => 'ژ',
  16731. 'ﮋ' => 'ژ',
  16732. 'ﮌ' => 'ڑ',
  16733. '�' => 'ڑ',
  16734. 'ﮎ' => 'ک',
  16735. '�' => 'ک',
  16736. '�' => 'ک',
  16737. 'ﮑ' => 'ک',
  16738. 'ï®’' => 'Ú¯',
  16739. 'ﮓ' => 'گ',
  16740. 'ï®”' => 'Ú¯',
  16741. 'ﮕ' => 'گ',
  16742. 'ï®–' => 'Ú³',
  16743. 'ï®—' => 'Ú³',
  16744. 'ﮘ' => 'ڳ',
  16745. 'ï®™' => 'Ú³',
  16746. 'ﮚ' => 'ڱ',
  16747. 'ï®›' => 'Ú±',
  16748. 'ﮜ' => 'ڱ',
  16749. '�' => 'ڱ',
  16750. 'ﮞ' => 'ں',
  16751. 'ﮟ' => 'ں',
  16752. 'ï® ' => 'Ú»',
  16753. 'ﮡ' => 'ڻ',
  16754. 'ﮢ' => 'ڻ',
  16755. 'ﮣ' => 'ڻ',
  16756. 'ﮤ' => 'ۀ',
  16757. 'ﮥ' => 'ۀ',
  16758. 'ﮦ' => '�',
  16759. 'ï®§' => 'Û�',
  16760. 'ﮨ' => '�',
  16761. 'ﮩ' => '�',
  16762. 'ﮪ' => 'ھ',
  16763. 'ﮫ' => 'ھ',
  16764. 'ﮬ' => 'ھ',
  16765. 'ï®­' => 'Ú¾',
  16766. 'ï®®' => 'Û’',
  16767. 'ﮯ' => 'ے',
  16768. 'ï®°' => 'Û’Ù”',
  16769. 'ï®±' => 'Û’Ù”',
  16770. 'ﯓ' => 'ڭ',
  16771. 'ﯔ' => 'ڭ',
  16772. 'ﯕ' => 'ڭ',
  16773. 'ﯖ' => 'ڭ',
  16774. 'ﯗ' => 'ۇ',
  16775. 'ﯘ' => 'ۇ',
  16776. 'ﯙ' => 'ۆ',
  16777. 'ﯚ' => 'ۆ',
  16778. 'ﯛ' => 'ۈ',
  16779. 'ﯜ' => 'ۈ',
  16780. '�' => 'ۇٴ',
  16781. 'ﯞ' => 'ۋ',
  16782. 'ﯟ' => 'ۋ',
  16783. 'ﯠ' => 'ۅ',
  16784. 'ﯡ' => 'ۅ',
  16785. 'ﯢ' => 'ۉ',
  16786. 'ﯣ' => 'ۉ',
  16787. 'ﯤ' => '�',
  16788. 'ﯥ' => '�',
  16789. 'ﯦ' => '�',
  16790. 'ﯧ' => '�',
  16791. 'ﯨ' => 'ى',
  16792. 'ﯩ' => 'ى',
  16793. 'ﯪ' => 'ئا',
  16794. 'ﯫ' => 'ئا',
  16795. 'ﯬ' => 'ئە',
  16796. 'ﯭ' => 'ئە',
  16797. 'ﯮ' => 'ئو',
  16798. 'ﯯ' => 'ئو',
  16799. 'ﯰ' => 'ئۇ',
  16800. 'ﯱ' => 'ئۇ',
  16801. 'ﯲ' => 'ئۆ',
  16802. 'ﯳ' => 'ئۆ',
  16803. 'ﯴ' => 'ئۈ',
  16804. 'ﯵ' => 'ئۈ',
  16805. 'ﯶ' => 'ئ�',
  16806. 'ﯷ' => 'ئ�',
  16807. 'ﯸ' => 'ئ�',
  16808. 'ﯹ' => 'ئى',
  16809. 'ﯺ' => 'ئى',
  16810. 'ﯻ' => 'ئى',
  16811. 'ﯼ' => 'ی',
  16812. 'ﯽ' => 'ی',
  16813. 'ﯾ' => 'ی',
  16814. 'ﯿ' => 'ی',
  16815. 'ﰀ' => 'ئج',
  16816. '�' => 'ئح',
  16817. 'ï°‚' => 'ÙŠÙ”Ù…',
  16818. 'ï°ƒ' => 'ÙŠÙ”Ù‰',
  16819. 'ï°„' => 'ÙŠÙ”ÙŠ',
  16820. 'ﰅ' => 'بج',
  16821. 'ﰆ' => 'بح',
  16822. 'ﰇ' => 'بخ',
  16823. 'ﰈ' => 'بم',
  16824. 'ﰉ' => 'بى',
  16825. 'ﰊ' => 'بي',
  16826. 'ﰋ' => 'تج',
  16827. 'ﰌ' => 'تح',
  16828. '�' => 'تخ',
  16829. 'ﰎ' => 'تم',
  16830. '�' => 'تى',
  16831. '�' => 'تي',
  16832. 'ﰑ' => 'ثج',
  16833. 'ﰒ' => 'ثم',
  16834. 'ﰓ' => 'ثى',
  16835. 'ﰔ' => 'ثي',
  16836. 'ﰕ' => 'جح',
  16837. 'ﰖ' => 'جم',
  16838. 'ﰗ' => 'حج',
  16839. 'ﰘ' => 'حم',
  16840. 'ﰙ' => 'خج',
  16841. 'ﰚ' => 'خح',
  16842. 'ﰛ' => 'خم',
  16843. 'ﰜ' => 'سج',
  16844. '�' => 'سح',
  16845. 'ﰞ' => 'سخ',
  16846. 'ﰟ' => 'سم',
  16847. 'ﰠ' => 'صح',
  16848. 'ﰡ' => 'صم',
  16849. 'ﰢ' => 'ضج',
  16850. 'ﰣ' => 'ضح',
  16851. 'ﰤ' => 'ضخ',
  16852. 'ﰥ' => 'ضم',
  16853. 'ﰦ' => 'طح',
  16854. 'ﰧ' => 'طم',
  16855. 'ﰨ' => 'ظم',
  16856. 'ﰩ' => 'عج',
  16857. 'ﰪ' => 'عم',
  16858. 'ﰫ' => 'غج',
  16859. 'ﰬ' => 'غم',
  16860. 'ﰭ' => '�ج',
  16861. 'ﰮ' => '�ح',
  16862. 'ﰯ' => '�خ',
  16863. 'ﰰ' => '�م',
  16864. 'ﰱ' => '�ى',
  16865. 'ﰲ' => '�ي',
  16866. 'ﰳ' => 'قح',
  16867. 'ﰴ' => 'قم',
  16868. 'ﰵ' => 'قى',
  16869. 'ﰶ' => 'قي',
  16870. 'ﰷ' => 'كا',
  16871. 'ﰸ' => 'كج',
  16872. 'ﰹ' => 'كح',
  16873. 'ﰺ' => 'كخ',
  16874. 'ﰻ' => 'كل',
  16875. 'ﰼ' => 'كم',
  16876. 'ﰽ' => 'كى',
  16877. 'ﰾ' => 'كي',
  16878. 'ﰿ' => 'لج',
  16879. 'ﱀ' => 'لح',
  16880. '�' => 'لخ',
  16881. 'ﱂ' => 'لم',
  16882. 'ﱃ' => 'لى',
  16883. 'ﱄ' => 'لي',
  16884. 'ﱅ' => 'مج',
  16885. 'ﱆ' => 'مح',
  16886. 'ﱇ' => 'مخ',
  16887. 'ﱈ' => 'مم',
  16888. 'ﱉ' => 'مى',
  16889. 'ﱊ' => 'مي',
  16890. 'ﱋ' => 'نج',
  16891. 'ﱌ' => 'نح',
  16892. '�' => 'نخ',
  16893. 'ﱎ' => 'نم',
  16894. '�' => 'نى',
  16895. '�' => 'ني',
  16896. 'ﱑ' => 'هج',
  16897. 'ﱒ' => 'هم',
  16898. 'ﱓ' => 'هى',
  16899. 'ﱔ' => 'هي',
  16900. 'ﱕ' => 'يج',
  16901. 'ﱖ' => 'يح',
  16902. 'ﱗ' => 'يخ',
  16903. 'ﱘ' => 'يم',
  16904. 'ﱙ' => 'يى',
  16905. 'ﱚ' => 'يي',
  16906. 'ﱛ' => 'ذٰ',
  16907. 'ﱜ' => 'رٰ',
  16908. '�' => 'ىٰ',
  16909. 'ﱞ' => ' ٌّ',
  16910. 'ﱟ' => ' �ّ',
  16911. 'ï± ' => ' ÙŽÙ‘',
  16912. 'ﱡ' => ' �ّ',
  16913. 'ﱢ' => ' �ّ',
  16914. 'ﱣ' => ' ّٰ',
  16915. 'ﱤ' => 'ئر',
  16916. 'ﱥ' => 'ئز',
  16917. 'ﱦ' => 'ئم',
  16918. 'ï±§' => 'ÙŠÙ”Ù†',
  16919. 'ﱨ' => 'ئى',
  16920. 'ﱩ' => 'ئي',
  16921. 'ﱪ' => 'بر',
  16922. 'ﱫ' => 'بز',
  16923. 'ﱬ' => 'بم',
  16924. 'ﱭ' => 'بن',
  16925. 'ﱮ' => 'بى',
  16926. 'ﱯ' => 'بي',
  16927. 'ﱰ' => 'تر',
  16928. 'ﱱ' => 'تز',
  16929. 'ﱲ' => 'تم',
  16930. 'ﱳ' => 'تن',
  16931. 'ﱴ' => 'تى',
  16932. 'ﱵ' => 'تي',
  16933. 'ﱶ' => 'ثر',
  16934. 'ﱷ' => 'ثز',
  16935. 'ﱸ' => 'ثم',
  16936. 'ﱹ' => 'ثن',
  16937. 'ﱺ' => 'ثى',
  16938. 'ﱻ' => 'ثي',
  16939. 'ﱼ' => '�ى',
  16940. 'ﱽ' => '�ي',
  16941. 'ﱾ' => 'قى',
  16942. 'ﱿ' => 'قي',
  16943. 'ﲀ' => 'كا',
  16944. '�' => 'كل',
  16945. 'ﲂ' => 'كم',
  16946. 'ﲃ' => 'كى',
  16947. 'ﲄ' => 'كي',
  16948. 'ﲅ' => 'لم',
  16949. 'ﲆ' => 'لى',
  16950. 'ﲇ' => 'لي',
  16951. 'ﲈ' => 'ما',
  16952. 'ﲉ' => 'مم',
  16953. 'ﲊ' => 'نر',
  16954. 'ﲋ' => 'نز',
  16955. 'ﲌ' => 'نم',
  16956. '�' => 'نن',
  16957. 'ﲎ' => 'نى',
  16958. '�' => 'ني',
  16959. '�' => 'ىٰ',
  16960. 'ﲑ' => 'ير',
  16961. 'ﲒ' => 'يز',
  16962. 'ﲓ' => 'يم',
  16963. 'ﲔ' => 'ين',
  16964. 'ﲕ' => 'يى',
  16965. 'ﲖ' => 'يي',
  16966. 'ﲗ' => 'ئج',
  16967. 'ﲘ' => 'ئح',
  16968. 'ﲙ' => 'ئخ',
  16969. 'ﲚ' => 'ئم',
  16970. 'ï²›' => 'ÙŠÙ”Ù‡',
  16971. 'ﲜ' => 'بج',
  16972. '�' => 'بح',
  16973. 'ﲞ' => 'بخ',
  16974. 'ﲟ' => 'بم',
  16975. 'ﲠ' => 'به',
  16976. 'ﲡ' => 'تج',
  16977. 'ﲢ' => 'تح',
  16978. 'ﲣ' => 'تخ',
  16979. 'ﲤ' => 'تم',
  16980. 'ﲥ' => 'ته',
  16981. 'ﲦ' => 'ثم',
  16982. 'ﲧ' => 'جح',
  16983. 'ﲨ' => 'جم',
  16984. 'ﲩ' => 'حج',
  16985. 'ﲪ' => 'حم',
  16986. 'ﲫ' => 'خج',
  16987. 'ﲬ' => 'خم',
  16988. 'ﲭ' => 'سج',
  16989. 'ﲮ' => 'سح',
  16990. 'ﲯ' => 'سخ',
  16991. 'ﲰ' => 'سم',
  16992. 'ﲱ' => 'صح',
  16993. 'ﲲ' => 'صخ',
  16994. 'ﲳ' => 'صم',
  16995. 'ﲴ' => 'ضج',
  16996. 'ﲵ' => 'ضح',
  16997. 'ﲶ' => 'ضخ',
  16998. 'ﲷ' => 'ضم',
  16999. 'ﲸ' => 'طح',
  17000. 'ﲹ' => 'ظم',
  17001. 'ﲺ' => 'عج',
  17002. 'ﲻ' => 'عم',
  17003. 'ﲼ' => 'غج',
  17004. 'ﲽ' => 'غم',
  17005. 'ﲾ' => '�ج',
  17006. 'ﲿ' => '�ح',
  17007. 'ﳀ' => '�خ',
  17008. '�' => '�م',
  17009. 'ﳂ' => 'قح',
  17010. 'ﳃ' => 'قم',
  17011. 'ﳄ' => 'كج',
  17012. 'ﳅ' => 'كح',
  17013. 'ﳆ' => 'كخ',
  17014. 'ﳇ' => 'كل',
  17015. 'ﳈ' => 'كم',
  17016. 'ﳉ' => 'لج',
  17017. 'ﳊ' => 'لح',
  17018. 'ﳋ' => 'لخ',
  17019. 'ﳌ' => 'لم',
  17020. '�' => 'له',
  17021. 'ﳎ' => 'مج',
  17022. '�' => 'مح',
  17023. '�' => 'مخ',
  17024. 'ﳑ' => 'مم',
  17025. 'ﳒ' => 'نج',
  17026. 'ﳓ' => 'نح',
  17027. 'ﳔ' => 'نخ',
  17028. 'ﳕ' => 'نم',
  17029. 'ﳖ' => 'نه',
  17030. 'ﳗ' => 'هج',
  17031. 'ﳘ' => 'هم',
  17032. 'ﳙ' => 'هٰ',
  17033. 'ﳚ' => 'يج',
  17034. 'ﳛ' => 'يح',
  17035. 'ﳜ' => 'يخ',
  17036. '�' => 'يم',
  17037. 'ﳞ' => 'يه',
  17038. 'ﳟ' => 'ئم',
  17039. 'ï³ ' => 'ÙŠÙ”Ù‡',
  17040. 'ﳡ' => 'بم',
  17041. 'ﳢ' => 'به',
  17042. 'ﳣ' => 'تم',
  17043. 'ﳤ' => 'ته',
  17044. 'ﳥ' => 'ثم',
  17045. 'ﳦ' => 'ثه',
  17046. 'ﳧ' => 'سم',
  17047. 'ﳨ' => 'سه',
  17048. 'ﳩ' => 'شم',
  17049. 'ﳪ' => 'شه',
  17050. 'ﳫ' => 'كل',
  17051. 'ﳬ' => 'كم',
  17052. 'ﳭ' => 'لم',
  17053. 'ﳮ' => 'نم',
  17054. 'ﳯ' => 'نه',
  17055. 'ﳰ' => 'يم',
  17056. 'ﳱ' => 'يه',
  17057. 'ï³²' => 'Ù€ÙŽÙ‘',
  17058. 'ﳳ' => 'ـ�ّ',
  17059. 'ﳴ' => 'ـ�ّ',
  17060. 'ﳵ' => 'طى',
  17061. 'ﳶ' => 'طي',
  17062. 'ﳷ' => 'عى',
  17063. 'ﳸ' => 'عي',
  17064. 'ﳹ' => 'غى',
  17065. 'ﳺ' => 'غي',
  17066. 'ﳻ' => 'سى',
  17067. 'ﳼ' => 'سي',
  17068. 'ﳽ' => 'شى',
  17069. 'ﳾ' => 'شي',
  17070. 'ﳿ' => 'حى',
  17071. 'ﴀ' => 'حي',
  17072. '�' => 'جى',
  17073. 'ﴂ' => 'جي',
  17074. 'ﴃ' => 'خى',
  17075. 'ﴄ' => 'خي',
  17076. 'ﴅ' => 'صى',
  17077. 'ﴆ' => 'صي',
  17078. 'ﴇ' => 'ضى',
  17079. 'ﴈ' => 'ضي',
  17080. 'ﴉ' => 'شج',
  17081. 'ﴊ' => 'شح',
  17082. 'ﴋ' => 'شخ',
  17083. 'ﴌ' => 'شم',
  17084. '�' => 'شر',
  17085. 'ﴎ' => 'سر',
  17086. '�' => 'صر',
  17087. '�' => 'ضر',
  17088. 'ﴑ' => 'طى',
  17089. 'ﴒ' => 'طي',
  17090. 'ﴓ' => 'عى',
  17091. 'ﴔ' => 'عي',
  17092. 'ﴕ' => 'غى',
  17093. 'ﴖ' => 'غي',
  17094. 'ﴗ' => 'سى',
  17095. 'ﴘ' => 'سي',
  17096. 'ﴙ' => 'شى',
  17097. 'ﴚ' => 'شي',
  17098. 'ﴛ' => 'حى',
  17099. 'ﴜ' => 'حي',
  17100. '�' => 'جى',
  17101. 'ﴞ' => 'جي',
  17102. 'ﴟ' => 'خى',
  17103. 'ﴠ' => 'خي',
  17104. 'ﴡ' => 'صى',
  17105. 'ﴢ' => 'صي',
  17106. 'ﴣ' => 'ضى',
  17107. 'ﴤ' => 'ضي',
  17108. 'ﴥ' => 'شج',
  17109. 'ﴦ' => 'شح',
  17110. 'ﴧ' => 'شخ',
  17111. 'ﴨ' => 'شم',
  17112. 'ﴩ' => 'شر',
  17113. 'ﴪ' => 'سر',
  17114. 'ﴫ' => 'صر',
  17115. 'ﴬ' => 'ضر',
  17116. 'ﴭ' => 'شج',
  17117. 'ﴮ' => 'شح',
  17118. 'ﴯ' => 'شخ',
  17119. 'ﴰ' => 'شم',
  17120. 'ﴱ' => 'سه',
  17121. 'ﴲ' => 'شه',
  17122. 'ﴳ' => 'طم',
  17123. 'ﴴ' => 'سج',
  17124. 'ﴵ' => 'سح',
  17125. 'ﴶ' => 'سخ',
  17126. 'ﴷ' => 'شج',
  17127. 'ﴸ' => 'شح',
  17128. 'ﴹ' => 'شخ',
  17129. 'ﴺ' => 'طم',
  17130. 'ﴻ' => 'ظم',
  17131. 'ﴼ' => 'اً',
  17132. 'ﴽ' => 'اً',
  17133. '�' => 'تجم',
  17134. 'ﵑ' => 'تحج',
  17135. 'ﵒ' => 'تحج',
  17136. 'ﵓ' => 'تحم',
  17137. 'ﵔ' => 'تخم',
  17138. 'ﵕ' => 'تمج',
  17139. 'ﵖ' => 'تمح',
  17140. 'ﵗ' => 'تمخ',
  17141. 'ﵘ' => 'جمح',
  17142. 'ﵙ' => 'جمح',
  17143. 'ﵚ' => 'حمي',
  17144. 'ﵛ' => 'حمى',
  17145. 'ﵜ' => 'سحج',
  17146. '�' => 'سجح',
  17147. 'ﵞ' => 'سجى',
  17148. 'ﵟ' => 'سمح',
  17149. 'ﵠ' => 'سمح',
  17150. 'ﵡ' => 'سمج',
  17151. 'ﵢ' => 'سمم',
  17152. 'ﵣ' => 'سمم',
  17153. 'ﵤ' => 'صحح',
  17154. 'ﵥ' => 'صحح',
  17155. 'ﵦ' => 'صمم',
  17156. 'ﵧ' => 'شحم',
  17157. 'ﵨ' => 'شحم',
  17158. 'ﵩ' => 'شجي',
  17159. 'ﵪ' => 'شمخ',
  17160. 'ﵫ' => 'شمخ',
  17161. 'ﵬ' => 'شمم',
  17162. 'ﵭ' => 'شمم',
  17163. 'ﵮ' => 'ضحى',
  17164. 'ﵯ' => 'ضخم',
  17165. 'ﵰ' => 'ضخم',
  17166. 'ﵱ' => 'طمح',
  17167. 'ﵲ' => 'طمح',
  17168. 'ﵳ' => 'طمم',
  17169. 'ﵴ' => 'طمي',
  17170. 'ﵵ' => 'عجم',
  17171. 'ﵶ' => 'عمم',
  17172. 'ﵷ' => 'عمم',
  17173. 'ﵸ' => 'عمى',
  17174. 'ﵹ' => 'غمم',
  17175. 'ﵺ' => 'غمي',
  17176. 'ﵻ' => 'غمى',
  17177. 'ﵼ' => '�خم',
  17178. 'ﵽ' => '�خم',
  17179. 'ﵾ' => 'قمح',
  17180. 'ﵿ' => 'قمم',
  17181. 'ﶀ' => 'لحم',
  17182. '�' => 'لحي',
  17183. 'ﶂ' => 'لحى',
  17184. 'ﶃ' => 'لجج',
  17185. 'ﶄ' => 'لجج',
  17186. 'ﶅ' => 'لخم',
  17187. 'ﶆ' => 'لخم',
  17188. 'ﶇ' => 'لمح',
  17189. 'ﶈ' => 'لمح',
  17190. 'ﶉ' => 'محج',
  17191. 'ﶊ' => 'محم',
  17192. 'ﶋ' => 'محي',
  17193. 'ﶌ' => 'مجح',
  17194. '�' => 'مجم',
  17195. 'ﶎ' => 'مخج',
  17196. '�' => 'مخم',
  17197. 'ﶒ' => 'مجخ',
  17198. 'ﶓ' => 'همج',
  17199. 'ﶔ' => 'همم',
  17200. 'ﶕ' => 'نحم',
  17201. 'ﶖ' => 'نحى',
  17202. 'ﶗ' => 'نجم',
  17203. 'ﶘ' => 'نجم',
  17204. 'ﶙ' => 'نجى',
  17205. 'ﶚ' => 'نمي',
  17206. 'ﶛ' => 'نمى',
  17207. 'ﶜ' => 'يمم',
  17208. '�' => 'يمم',
  17209. 'ﶞ' => 'بخي',
  17210. 'ﶟ' => 'تجي',
  17211. 'ﶠ' => 'تجى',
  17212. 'ﶡ' => 'تخي',
  17213. 'ﶢ' => 'تخى',
  17214. 'ﶣ' => 'تمي',
  17215. 'ﶤ' => 'تمى',
  17216. 'ﶥ' => 'جمي',
  17217. 'ﶦ' => 'جحى',
  17218. 'ﶧ' => 'جمى',
  17219. 'ﶨ' => 'سخى',
  17220. 'ﶩ' => 'صحي',
  17221. 'ﶪ' => 'شحي',
  17222. 'ﶫ' => 'ضحي',
  17223. 'ﶬ' => 'لجي',
  17224. 'ﶭ' => 'لمي',
  17225. 'ﶮ' => 'يحي',
  17226. 'ﶯ' => 'يجي',
  17227. 'ﶰ' => 'يمي',
  17228. 'ﶱ' => 'ممي',
  17229. 'ﶲ' => 'قمي',
  17230. 'ﶳ' => 'نحي',
  17231. 'ﶴ' => 'قمح',
  17232. 'ﶵ' => 'لحم',
  17233. 'ﶶ' => 'عمي',
  17234. 'ﶷ' => 'كمي',
  17235. 'ﶸ' => 'نجح',
  17236. 'ﶹ' => 'مخي',
  17237. 'ﶺ' => 'لجم',
  17238. 'ﶻ' => 'كمم',
  17239. 'ﶼ' => 'لجم',
  17240. 'ﶽ' => 'نجح',
  17241. 'ﶾ' => 'جحي',
  17242. 'ﶿ' => 'حجي',
  17243. 'ﷀ' => 'مجي',
  17244. '�' => '�مي',
  17245. 'ﷂ' => 'بحي',
  17246. 'ﷃ' => 'كمم',
  17247. 'ﷄ' => 'عجم',
  17248. 'ﷅ' => 'صمم',
  17249. 'ﷆ' => 'سخي',
  17250. 'ﷇ' => 'نجي',
  17251. 'ﷰ' => 'صلے',
  17252. 'ﷱ' => 'قلے',
  17253. 'ﷲ' => 'الله',
  17254. 'ﷳ' => 'اكبر',
  17255. 'ﷴ' => 'محمد',
  17256. 'ﷵ' => 'صلعم',
  17257. 'ﷶ' => 'رسول',
  17258. 'ﷷ' => 'عليه',
  17259. 'ﷸ' => 'وسلم',
  17260. 'ﷹ' => 'صلى',
  17261. 'ﷺ' => 'صلى الله عليه وسلم',
  17262. 'ﷻ' => 'جل جلاله',
  17263. '﷼' => 'ریال',
  17264. '�' => ',',
  17265. '︑' => '�',
  17266. '︒' => '。',
  17267. '︓' => ':',
  17268. '︔' => ';',
  17269. '︕' => '!',
  17270. '︖' => '?',
  17271. '︗' => '〖',
  17272. '︘' => '〗',
  17273. '︙' => '...',
  17274. '︰' => '..',
  17275. '︱' => '—',
  17276. '︲' => '–',
  17277. '︳' => '_',
  17278. '︴' => '_',
  17279. '︵' => '(',
  17280. '︶' => ')',
  17281. '︷' => '{',
  17282. '︸' => '}',
  17283. '︹' => '〔',
  17284. '︺' => '〕',
  17285. '︻' => '�',
  17286. '︼' => '】',
  17287. '︽' => '《',
  17288. '︾' => '》',
  17289. '︿' => '〈',
  17290. '﹀' => '〉',
  17291. '�' => '「',
  17292. '﹂' => '�',
  17293. '﹃' => '『',
  17294. '﹄' => '�',
  17295. '﹇' => '[',
  17296. '﹈' => ']',
  17297. '﹉' => ' ̅',
  17298. '﹊' => ' ̅',
  17299. '﹋' => ' ̅',
  17300. '﹌' => ' ̅',
  17301. '�' => '_',
  17302. '﹎' => '_',
  17303. '�' => '_',
  17304. '�' => ',',
  17305. '﹑' => '�',
  17306. 'ï¹’' => '.',
  17307. 'ï¹”' => ';',
  17308. '﹕' => ':',
  17309. 'ï¹–' => '?',
  17310. 'ï¹—' => '!',
  17311. '﹘' => '—',
  17312. 'ï¹™' => '(',
  17313. '﹚' => ')',
  17314. 'ï¹›' => '{',
  17315. '﹜' => '}',
  17316. '�' => '〔',
  17317. '﹞' => '〕',
  17318. '﹟' => '#',
  17319. 'ï¹ ' => '&',
  17320. '﹡' => '*',
  17321. 'ï¹¢' => '+',
  17322. 'ï¹£' => '-',
  17323. '﹤' => '<',
  17324. 'ï¹¥' => '>',
  17325. '﹦' => '=',
  17326. '﹨' => '\\',
  17327. '﹩' => '$',
  17328. '﹪' => '%',
  17329. '﹫' => '@',
  17330. 'ï¹°' => ' Ù‹',
  17331. 'ﹱ' => 'ـً',
  17332. 'ﹲ' => ' ٌ',
  17333. 'ï¹´' => ' Ù�',
  17334. 'ï¹¶' => ' ÙŽ',
  17335. 'ï¹·' => 'Ù€ÙŽ',
  17336. 'ﹸ' => ' �',
  17337. 'ﹹ' => 'ـ�',
  17338. 'ﹺ' => ' �',
  17339. 'ﹻ' => 'ـ�',
  17340. 'ï¹¼' => ' Ù‘',
  17341. 'ﹽ' => 'ـّ',
  17342. 'ï¹¾' => ' Ù’',
  17343. 'ﹿ' => 'ـْ',
  17344. 'ﺀ' => 'ء',
  17345. '�' => 'آ',
  17346. 'ﺂ' => 'آ',
  17347. 'ﺃ' => 'أ',
  17348. 'ﺄ' => 'أ',
  17349. 'ﺅ' => 'ؤ',
  17350. 'ﺆ' => 'ؤ',
  17351. 'ﺇ' => 'إ',
  17352. 'ﺈ' => 'إ',
  17353. 'ﺉ' => 'ئ',
  17354. 'ﺊ' => 'ئ',
  17355. 'ﺋ' => 'ئ',
  17356. 'ﺌ' => 'ئ',
  17357. '�' => 'ا',
  17358. 'ﺎ' => 'ا',
  17359. '�' => 'ب',
  17360. '�' => 'ب',
  17361. 'ﺑ' => 'ب',
  17362. 'ﺒ' => 'ب',
  17363. 'ﺓ' => 'ة',
  17364. 'ﺔ' => 'ة',
  17365. 'ﺕ' => 'ت',
  17366. 'ﺖ' => 'ت',
  17367. 'ﺗ' => 'ت',
  17368. 'ﺘ' => 'ت',
  17369. 'ﺙ' => 'ث',
  17370. 'ﺚ' => 'ث',
  17371. 'ﺛ' => 'ث',
  17372. 'ﺜ' => 'ث',
  17373. '�' => 'ج',
  17374. 'ﺞ' => 'ج',
  17375. 'ﺟ' => 'ج',
  17376. 'ﺠ' => 'ج',
  17377. 'ﺡ' => 'ح',
  17378. 'ﺢ' => 'ح',
  17379. 'ﺣ' => 'ح',
  17380. 'ﺤ' => 'ح',
  17381. 'ﺥ' => 'خ',
  17382. 'ﺦ' => 'خ',
  17383. 'ﺧ' => 'خ',
  17384. 'ﺨ' => 'خ',
  17385. 'ﺩ' => 'د',
  17386. 'ﺪ' => 'د',
  17387. 'ﺫ' => 'ذ',
  17388. 'ﺬ' => 'ذ',
  17389. 'ﺭ' => 'ر',
  17390. 'ﺮ' => 'ر',
  17391. 'ﺯ' => 'ز',
  17392. 'ﺰ' => 'ز',
  17393. 'ﺱ' => 'س',
  17394. 'ﺲ' => 'س',
  17395. 'ﺳ' => 'س',
  17396. 'ﺴ' => 'س',
  17397. 'ﺵ' => 'ش',
  17398. 'ﺶ' => 'ش',
  17399. 'ﺷ' => 'ش',
  17400. 'ﺸ' => 'ش',
  17401. 'ﺹ' => 'ص',
  17402. 'ﺺ' => 'ص',
  17403. 'ﺻ' => 'ص',
  17404. 'ﺼ' => 'ص',
  17405. 'ﺽ' => 'ض',
  17406. 'ﺾ' => 'ض',
  17407. 'ﺿ' => 'ض',
  17408. 'ﻀ' => 'ض',
  17409. '�' => 'ط',
  17410. 'ﻂ' => 'ط',
  17411. 'ﻃ' => 'ط',
  17412. 'ﻄ' => 'ط',
  17413. 'ﻅ' => 'ظ',
  17414. 'ﻆ' => 'ظ',
  17415. 'ﻇ' => 'ظ',
  17416. 'ﻈ' => 'ظ',
  17417. 'ﻉ' => 'ع',
  17418. 'ﻊ' => 'ع',
  17419. 'ﻋ' => 'ع',
  17420. 'ﻌ' => 'ع',
  17421. '�' => 'غ',
  17422. 'ﻎ' => 'غ',
  17423. '�' => 'غ',
  17424. '�' => 'غ',
  17425. 'ﻑ' => '�',
  17426. 'ï»’' => 'Ù�',
  17427. 'ﻓ' => '�',
  17428. 'ï»”' => 'Ù�',
  17429. 'ﻕ' => 'ق',
  17430. 'ï»–' => 'Ù‚',
  17431. 'ï»—' => 'Ù‚',
  17432. 'ﻘ' => 'ق',
  17433. 'ï»™' => 'Ùƒ',
  17434. 'ﻚ' => 'ك',
  17435. 'ï»›' => 'Ùƒ',
  17436. 'ﻜ' => 'ك',
  17437. '�' => 'ل',
  17438. 'ﻞ' => 'ل',
  17439. 'ﻟ' => 'ل',
  17440. 'ï» ' => 'Ù„',
  17441. 'ﻡ' => 'م',
  17442. 'ﻢ' => 'م',
  17443. 'ﻣ' => 'م',
  17444. 'ﻤ' => 'م',
  17445. 'ﻥ' => 'ن',
  17446. 'ﻦ' => 'ن',
  17447. 'ï»§' => 'Ù†',
  17448. 'ﻨ' => 'ن',
  17449. 'ﻩ' => 'ه',
  17450. 'ﻪ' => 'ه',
  17451. 'ﻫ' => 'ه',
  17452. 'ﻬ' => 'ه',
  17453. 'ï»­' => 'Ùˆ',
  17454. 'ï»®' => 'Ùˆ',
  17455. 'ﻯ' => 'ى',
  17456. 'ï»°' => 'Ù‰',
  17457. 'ï»±' => 'ÙŠ',
  17458. 'ﻲ' => 'ي',
  17459. 'ﻳ' => 'ي',
  17460. 'ï»´' => 'ÙŠ',
  17461. 'ﻵ' => 'لآ',
  17462. 'ﻶ' => 'لآ',
  17463. 'ﻷ' => 'لأ',
  17464. 'ﻸ' => 'لأ',
  17465. 'ﻹ' => 'لإ',
  17466. 'ﻺ' => 'لإ',
  17467. 'ﻻ' => 'لا',
  17468. 'ﻼ' => 'لا',
  17469. '�' => '!',
  17470. '"' => '"',
  17471. '#' => '#',
  17472. '$' => '$',
  17473. 'ï¼…' => '%',
  17474. '&' => '&',
  17475. ''' => '\'',
  17476. '(' => '(',
  17477. ')' => ')',
  17478. '*' => '*',
  17479. '+' => '+',
  17480. ',' => ',',
  17481. '�' => '-',
  17482. '.' => '.',
  17483. '�' => '/',
  17484. '�' => '0',
  17485. '1' => '1',
  17486. 'ï¼’' => '2',
  17487. '3' => '3',
  17488. 'ï¼”' => '4',
  17489. '5' => '5',
  17490. 'ï¼–' => '6',
  17491. 'ï¼—' => '7',
  17492. '8' => '8',
  17493. 'ï¼™' => '9',
  17494. ':' => ':',
  17495. 'ï¼›' => ';',
  17496. '<' => '<',
  17497. '�' => '=',
  17498. '>' => '>',
  17499. '?' => '?',
  17500. 'ï¼ ' => '@',
  17501. 'A' => 'A',
  17502. 'ï¼¢' => 'B',
  17503. 'ï¼£' => 'C',
  17504. 'D' => 'D',
  17505. 'ï¼¥' => 'E',
  17506. 'F' => 'F',
  17507. 'ï¼§' => 'G',
  17508. 'H' => 'H',
  17509. 'I' => 'I',
  17510. 'J' => 'J',
  17511. 'K' => 'K',
  17512. 'L' => 'L',
  17513. 'ï¼­' => 'M',
  17514. 'ï¼®' => 'N',
  17515. 'O' => 'O',
  17516. 'ï¼°' => 'P',
  17517. 'ï¼±' => 'Q',
  17518. 'ï¼²' => 'R',
  17519. 'ï¼³' => 'S',
  17520. 'ï¼´' => 'T',
  17521. 'ï¼µ' => 'U',
  17522. 'ï¼¶' => 'V',
  17523. 'ï¼·' => 'W',
  17524. 'X' => 'X',
  17525. 'ï¼¹' => 'Y',
  17526. 'Z' => 'Z',
  17527. 'ï¼»' => '[',
  17528. 'ï¼¼' => '\\',
  17529. 'ï¼½' => ']',
  17530. 'ï¼¾' => '^',
  17531. '_' => '_',
  17532. 'ï½€' => '`',
  17533. '�' => 'a',
  17534. 'b' => 'b',
  17535. 'c' => 'c',
  17536. 'd' => 'd',
  17537. 'ï½…' => 'e',
  17538. 'f' => 'f',
  17539. 'g' => 'g',
  17540. 'h' => 'h',
  17541. 'i' => 'i',
  17542. 'j' => 'j',
  17543. 'k' => 'k',
  17544. 'l' => 'l',
  17545. '�' => 'm',
  17546. 'n' => 'n',
  17547. '�' => 'o',
  17548. '�' => 'p',
  17549. 'q' => 'q',
  17550. 'ï½’' => 'r',
  17551. 's' => 's',
  17552. 'ï½”' => 't',
  17553. 'u' => 'u',
  17554. 'ï½–' => 'v',
  17555. 'ï½—' => 'w',
  17556. 'x' => 'x',
  17557. 'ï½™' => 'y',
  17558. 'z' => 'z',
  17559. 'ï½›' => '{',
  17560. '|' => '|',
  17561. '�' => '}',
  17562. '~' => '~',
  17563. '⦅' => '⦅',
  17564. '⦆' => '⦆',
  17565. '。' => '。',
  17566. '「' => '「',
  17567. '」' => '�',
  17568. '、' => '�',
  17569. '・' => '・',
  17570. 'ヲ' => 'ヲ',
  17571. 'ï½§' => 'ã‚¡',
  17572. 'ィ' => 'ィ',
  17573. 'ゥ' => 'ゥ',
  17574. 'ェ' => 'ェ',
  17575. 'ォ' => 'ォ',
  17576. 'ャ' => 'ャ',
  17577. 'ュ' => 'ュ',
  17578. 'ョ' => 'ョ',
  17579. 'ッ' => 'ッ',
  17580. 'ー' => 'ー',
  17581. 'ï½±' => 'ã‚¢',
  17582. 'イ' => 'イ',
  17583. 'ウ' => 'ウ',
  17584. 'エ' => 'エ',
  17585. 'オ' => 'オ',
  17586. 'ï½¶' => 'ã‚«',
  17587. 'ï½·' => 'ã‚­',
  17588. 'ク' => 'ク',
  17589. 'ケ' => 'ケ',
  17590. 'コ' => 'コ',
  17591. 'サ' => 'サ',
  17592. 'ï½¼' => 'ã‚·',
  17593. 'ス' => 'ス',
  17594. 'ï½¾' => 'ã‚»',
  17595. 'ソ' => 'ソ',
  17596. 'ï¾€' => 'ã‚¿',
  17597. '�' => '�',
  17598. 'ツ' => 'ツ',
  17599. 'テ' => 'テ',
  17600. 'ト' => 'ト',
  17601. 'ナ' => 'ナ',
  17602. 'ニ' => 'ニ',
  17603. 'ヌ' => 'ヌ',
  17604. 'ネ' => '�',
  17605. 'ノ' => 'ノ',
  17606. 'ハ' => '�',
  17607. 'ヒ' => 'ヒ',
  17608. 'フ' => 'フ',
  17609. '�' => 'ヘ',
  17610. 'ホ' => 'ホ',
  17611. '�' => 'マ',
  17612. '�' => 'ミ',
  17613. 'ム' => 'ム',
  17614. 'メ' => 'メ',
  17615. 'モ' => 'モ',
  17616. 'ヤ' => 'ヤ',
  17617. 'ユ' => 'ユ',
  17618. 'ヨ' => 'ヨ',
  17619. 'ラ' => 'ラ',
  17620. 'リ' => 'リ',
  17621. 'ル' => 'ル',
  17622. 'レ' => 'レ',
  17623. 'ロ' => 'ロ',
  17624. 'ワ' => 'ワ',
  17625. '�' => 'ン',
  17626. '゙' => '゙',
  17627. '゚' => '゚',
  17628. 'ï¾ ' => 'á… ',
  17629. 'ᄀ' => 'ᄀ',
  17630. 'ᄁ' => '�',
  17631. 'ᆪ' => 'ᆪ',
  17632. 'ᄂ' => 'ᄂ',
  17633. 'ᆬ' => 'ᆬ',
  17634. 'ᆭ' => 'ᆭ',
  17635. 'ᄃ' => 'ᄃ',
  17636. 'ᄄ' => 'ᄄ',
  17637. 'ᄅ' => 'ᄅ',
  17638. 'ᆰ' => 'ᆰ',
  17639. 'ᆱ' => 'ᆱ',
  17640. 'ᆲ' => 'ᆲ',
  17641. 'ᆳ' => 'ᆳ',
  17642. 'ᆴ' => 'ᆴ',
  17643. 'ᆵ' => 'ᆵ',
  17644. 'ᄚ' => 'ᄚ',
  17645. 'ᄆ' => 'ᄆ',
  17646. 'ᄇ' => 'ᄇ',
  17647. 'ᄈ' => 'ᄈ',
  17648. 'ï¾´' => 'á„¡',
  17649. 'ᄉ' => 'ᄉ',
  17650. 'ᄊ' => 'ᄊ',
  17651. 'ï¾·' => 'á„‹',
  17652. 'ᄌ' => 'ᄌ',
  17653. 'ᄍ' => '�',
  17654. 'ᄎ' => 'ᄎ',
  17655. 'ᄏ' => '�',
  17656. 'ᄐ' => '�',
  17657. 'ï¾½' => 'á„‘',
  17658. 'ï¾¾' => 'á„’',
  17659. 'ï¿‚' => 'á…¡',
  17660. 'ᅢ' => 'ᅢ',
  17661. 'ï¿„' => 'á…£',
  17662. 'ï¿…' => 'á…¤',
  17663. 'ᅥ' => 'ᅥ',
  17664. 'ᅦ' => 'ᅦ',
  17665. 'ᅧ' => 'ᅧ',
  17666. 'ï¿‹' => 'á…¨',
  17667. 'ᅩ' => 'ᅩ',
  17668. '�' => 'ᅪ',
  17669. 'ᅫ' => 'ᅫ',
  17670. '�' => 'ᅬ',
  17671. 'ï¿’' => 'á…­',
  17672. 'ï¿“' => 'á…®',
  17673. 'ï¿”' => 'á…¯',
  17674. 'ï¿•' => 'á…°',
  17675. 'ï¿–' => 'á…±',
  17676. 'ï¿—' => 'á…²',
  17677. 'ᅳ' => 'ᅳ',
  17678. 'ï¿›' => 'á…´',
  17679. 'ᅵ' => 'ᅵ',
  17680. '¢' => '¢',
  17681. '£' => '£',
  17682. '¬' => '¬',
  17683. 'ï¿£' => ' Ì„',
  17684. '¦' => '¦',
  17685. 'ï¿¥' => 'Â¥',
  17686. '₩' => '₩',
  17687. '│' => '│',
  17688. '←' => '�',
  17689. '↑' => '↑',
  17690. '→' => '→',
  17691. '↓' => '↓',
  17692. 'ï¿­' => 'â– ',
  17693. 'ï¿®' => 'â—‹',
  17694. '�' => 'A',
  17695. '�' => 'B',
  17696. '�' => 'C',
  17697. '�' => 'D',
  17698. '�' => 'E',
  17699. '�' => 'F',
  17700. '�' => 'G',
  17701. '�' => 'H',
  17702. '�' => 'I',
  17703. '�' => 'J',
  17704. '�' => 'K',
  17705. '�' => 'L',
  17706. '�' => 'M',
  17707. '�' => 'N',
  17708. '�' => 'O',
  17709. '�' => 'P',
  17710. '�' => 'Q',
  17711. '�' => 'R',
  17712. '�' => 'S',
  17713. '�' => 'T',
  17714. '�' => 'U',
  17715. '�' => 'V',
  17716. '�' => 'W',
  17717. '�' => 'X',
  17718. '�' => 'Y',
  17719. '�' => 'Z',
  17720. '�' => 'a',
  17721. '�' => 'b',
  17722. '�' => 'c',
  17723. '�' => 'd',
  17724. '�' => 'e',
  17725. '�' => 'f',
  17726. '�' => 'g',
  17727. '�' => 'h',
  17728. '�' => 'i',
  17729. '�' => 'j',
  17730. '�' => 'k',
  17731. '�' => 'l',
  17732. '�' => 'm',
  17733. '�' => 'n',
  17734. '�' => 'o',
  17735. '�' => 'p',
  17736. '�' => 'q',
  17737. '�' => 'r',
  17738. '�' => 's',
  17739. '�' => 't',
  17740. '�' => 'u',
  17741. '�' => 'v',
  17742. '�' => 'w',
  17743. '�' => 'x',
  17744. '�' => 'y',
  17745. '�' => 'z',
  17746. '�' => 'A',
  17747. '�' => 'B',
  17748. '�' => 'C',
  17749. '�' => 'D',
  17750. '�' => 'E',
  17751. '�' => 'F',
  17752. '�' => 'G',
  17753. '�' => 'H',
  17754. '�' => 'I',
  17755. '�' => 'J',
  17756. '�' => 'K',
  17757. '�' => 'L',
  17758. '�' => 'M',
  17759. '�' => 'N',
  17760. '�' => 'O',
  17761. '�' => 'P',
  17762. '�' => 'Q',
  17763. '�' => 'R',
  17764. '�' => 'S',
  17765. '�' => 'T',
  17766. '�' => 'U',
  17767. '�' => 'V',
  17768. '�' => 'W',
  17769. '�' => 'X',
  17770. '�' => 'Y',
  17771. '�' => 'Z',
  17772. '�' => 'a',
  17773. '�' => 'b',
  17774. '�' => 'c',
  17775. '�' => 'd',
  17776. '�' => 'e',
  17777. '�' => 'f',
  17778. '�' => 'g',
  17779. '�' => 'i',
  17780. '�' => 'j',
  17781. '�' => 'k',
  17782. '�' => 'l',
  17783. '�' => 'm',
  17784. '�' => 'n',
  17785. '�' => 'o',
  17786. '�' => 'p',
  17787. '�' => 'q',
  17788. '�' => 'r',
  17789. '�' => 's',
  17790. '�' => 't',
  17791. '�' => 'u',
  17792. '�' => 'v',
  17793. '�' => 'w',
  17794. '�' => 'x',
  17795. '�' => 'y',
  17796. '�' => 'z',
  17797. '�' => 'A',
  17798. '�' => 'B',
  17799. '�' => 'C',
  17800. '�' => 'D',
  17801. '�' => 'E',
  17802. '�' => 'F',
  17803. '�' => 'G',
  17804. '�' => 'H',
  17805. '�' => 'I',
  17806. '�' => 'J',
  17807. '�' => 'K',
  17808. '�' => 'L',
  17809. '�' => 'M',
  17810. '�' => 'N',
  17811. '�' => 'O',
  17812. '�' => 'P',
  17813. '�' => 'Q',
  17814. '�' => 'R',
  17815. '�' => 'S',
  17816. '�' => 'T',
  17817. '�' => 'U',
  17818. '�' => 'V',
  17819. '�' => 'W',
  17820. '�' => 'X',
  17821. '�' => 'Y',
  17822. '�' => 'Z',
  17823. '�' => 'a',
  17824. '�' => 'b',
  17825. '�' => 'c',
  17826. '�' => 'd',
  17827. '�' => 'e',
  17828. '�' => 'f',
  17829. '�' => 'g',
  17830. '�' => 'h',
  17831. '�' => 'i',
  17832. '�' => 'j',
  17833. '�' => 'k',
  17834. '�' => 'l',
  17835. '�' => 'm',
  17836. '�' => 'n',
  17837. '�' => 'o',
  17838. '�' => 'p',
  17839. '�' => 'q',
  17840. '�' => 'r',
  17841. '�' => 's',
  17842. '�' => 't',
  17843. '�' => 'u',
  17844. '�' => 'v',
  17845. '�' => 'w',
  17846. '�' => 'x',
  17847. '�' => 'y',
  17848. '�' => 'z',
  17849. '�' => 'A',
  17850. '�' => 'C',
  17851. '�' => 'D',
  17852. '�' => 'G',
  17853. '�' => 'J',
  17854. '�' => 'K',
  17855. '�' => 'N',
  17856. '�' => 'O',
  17857. '�' => 'P',
  17858. '�' => 'Q',
  17859. '�' => 'S',
  17860. '�' => 'T',
  17861. '�' => 'U',
  17862. '�' => 'V',
  17863. '�' => 'W',
  17864. '�' => 'X',
  17865. '�' => 'Y',
  17866. '�' => 'Z',
  17867. '�' => 'a',
  17868. '�' => 'b',
  17869. '�' => 'c',
  17870. '�' => 'd',
  17871. '�' => 'f',
  17872. '�' => 'h',
  17873. '�' => 'i',
  17874. '�' => 'j',
  17875. '�' => 'k',
  17876. '�' => 'l',
  17877. '�' => 'm',
  17878. '�' => 'n',
  17879. '�' => 'p',
  17880. '�' => 'q',
  17881. '�' => 'r',
  17882. '�' => 's',
  17883. '�' => 't',
  17884. '�' => 'u',
  17885. '�' => 'v',
  17886. '�' => 'w',
  17887. '�' => 'x',
  17888. '�' => 'y',
  17889. '�' => 'z',
  17890. '�' => 'A',
  17891. '�' => 'B',
  17892. '�' => 'C',
  17893. '�' => 'D',
  17894. '�' => 'E',
  17895. '�' => 'F',
  17896. '�' => 'G',
  17897. '�' => 'H',
  17898. '�' => 'I',
  17899. '�' => 'J',
  17900. '�' => 'K',
  17901. '�' => 'L',
  17902. '�' => 'M',
  17903. '�' => 'N',
  17904. '�' => 'O',
  17905. '�' => 'P',
  17906. '�' => 'Q',
  17907. '�' => 'R',
  17908. '�' => 'S',
  17909. '�' => 'T',
  17910. '�' => 'U',
  17911. '�' => 'V',
  17912. '�' => 'W',
  17913. '�' => 'X',
  17914. '�' => 'Y',
  17915. '�' => 'Z',
  17916. '�' => 'a',
  17917. '�' => 'b',
  17918. '�' => 'c',
  17919. '�' => 'd',
  17920. '�' => 'e',
  17921. '�' => 'f',
  17922. '�' => 'g',
  17923. '�' => 'h',
  17924. '�' => 'i',
  17925. '�' => 'j',
  17926. '�' => 'k',
  17927. '�' => 'l',
  17928. '�' => 'm',
  17929. '�' => 'n',
  17930. '�' => 'o',
  17931. '�' => 'p',
  17932. '�' => 'q',
  17933. '�' => 'r',
  17934. '�' => 's',
  17935. '�' => 't',
  17936. '�' => 'u',
  17937. '�' => 'v',
  17938. '�' => 'w',
  17939. '�' => 'x',
  17940. '�' => 'y',
  17941. '�' => 'z',
  17942. '�' => 'A',
  17943. '�' => 'B',
  17944. '�' => 'D',
  17945. '�' => 'E',
  17946. '�' => 'F',
  17947. '�' => 'G',
  17948. '�' => 'J',
  17949. '�' => 'K',
  17950. '�' => 'L',
  17951. '�' => 'M',
  17952. '�' => 'N',
  17953. '�' => 'O',
  17954. '�' => 'P',
  17955. '�' => 'Q',
  17956. '�' => 'S',
  17957. '�' => 'T',
  17958. '�' => 'U',
  17959. '�' => 'V',
  17960. '�' => 'W',
  17961. '�' => 'X',
  17962. '�' => 'Y',
  17963. '�' => 'a',
  17964. '�' => 'b',
  17965. '�' => 'c',
  17966. '�' => 'd',
  17967. '�' => 'e',
  17968. '�' => 'f',
  17969. '�' => 'g',
  17970. '�' => 'h',
  17971. '�' => 'i',
  17972. '�' => 'j',
  17973. '�' => 'k',
  17974. '�' => 'l',
  17975. '�' => 'm',
  17976. '�' => 'n',
  17977. '�' => 'o',
  17978. '�' => 'p',
  17979. '�' => 'q',
  17980. '�' => 'r',
  17981. '�' => 's',
  17982. '�' => 't',
  17983. '�' => 'u',
  17984. '�' => 'v',
  17985. '�' => 'w',
  17986. '�' => 'x',
  17987. '�' => 'y',
  17988. '�' => 'z',
  17989. '�' => 'A',
  17990. '�' => 'B',
  17991. '�' => 'D',
  17992. '�' => 'E',
  17993. '�' => 'F',
  17994. '�' => 'G',
  17995. '�' => 'I',
  17996. '�' => 'J',
  17997. '�' => 'K',
  17998. '�' => 'L',
  17999. '�' => 'M',
  18000. '�' => 'O',
  18001. '�' => 'S',
  18002. '�' => 'T',
  18003. '�' => 'U',
  18004. '�' => 'V',
  18005. '�' => 'W',
  18006. '�' => 'X',
  18007. '�' => 'Y',
  18008. '�' => 'a',
  18009. '�' => 'b',
  18010. '�' => 'c',
  18011. '�' => 'd',
  18012. '�' => 'e',
  18013. '�' => 'f',
  18014. '�' => 'g',
  18015. '�' => 'h',
  18016. '�' => 'i',
  18017. '�' => 'j',
  18018. '�' => 'k',
  18019. '�' => 'l',
  18020. '�' => 'm',
  18021. '�' => 'n',
  18022. '�' => 'o',
  18023. '�' => 'p',
  18024. '�' => 'q',
  18025. '�' => 'r',
  18026. '�' => 's',
  18027. '�' => 't',
  18028. '�' => 'u',
  18029. '�' => 'v',
  18030. '�' => 'w',
  18031. '�' => 'x',
  18032. '�' => 'y',
  18033. '�' => 'z',
  18034. '�' => 'A',
  18035. '�' => 'B',
  18036. '�' => 'C',
  18037. '�' => 'D',
  18038. '�' => 'E',
  18039. '�' => 'F',
  18040. '�' => 'G',
  18041. '�' => 'H',
  18042. '�' => 'I',
  18043. '�' => 'J',
  18044. '�' => 'K',
  18045. '�' => 'L',
  18046. '�' => 'M',
  18047. '�' => 'N',
  18048. '�' => 'O',
  18049. '�' => 'P',
  18050. '�' => 'Q',
  18051. '�' => 'R',
  18052. '�' => 'S',
  18053. '�' => 'T',
  18054. '�' => 'U',
  18055. '�' => 'V',
  18056. '�' => 'W',
  18057. '�' => 'X',
  18058. '�' => 'Y',
  18059. '�' => 'Z',
  18060. '�' => 'a',
  18061. '�' => 'b',
  18062. '�' => 'c',
  18063. '�' => 'd',
  18064. '�' => 'e',
  18065. '�' => 'f',
  18066. '�' => 'g',
  18067. '�' => 'h',
  18068. '�' => 'i',
  18069. '�' => 'j',
  18070. '�' => 'k',
  18071. '�' => 'l',
  18072. '�' => 'm',
  18073. '�' => 'n',
  18074. '�' => 'o',
  18075. '�' => 'p',
  18076. '�' => 'q',
  18077. '�' => 'r',
  18078. '�' => 's',
  18079. '�' => 't',
  18080. '�' => 'u',
  18081. '�' => 'v',
  18082. '�' => 'w',
  18083. '�' => 'x',
  18084. '�' => 'y',
  18085. '�' => 'z',
  18086. '�' => 'A',
  18087. '�' => 'B',
  18088. '�' => 'C',
  18089. '�' => 'D',
  18090. '�' => 'E',
  18091. '�' => 'F',
  18092. '�' => 'G',
  18093. '�' => 'H',
  18094. '�' => 'I',
  18095. '�' => 'J',
  18096. '�' => 'K',
  18097. '�' => 'L',
  18098. '�' => 'M',
  18099. '�' => 'N',
  18100. '�' => 'O',
  18101. '�' => 'P',
  18102. '�' => 'Q',
  18103. '�' => 'R',
  18104. '�' => 'S',
  18105. '�' => 'T',
  18106. '�' => 'U',
  18107. '�' => 'V',
  18108. '�' => 'W',
  18109. '�' => 'X',
  18110. '�' => 'Y',
  18111. '�' => 'Z',
  18112. '�' => 'a',
  18113. '�' => 'b',
  18114. '�' => 'c',
  18115. '�' => 'd',
  18116. '�' => 'e',
  18117. '�' => 'f',
  18118. '�' => 'g',
  18119. '�' => 'h',
  18120. '�' => 'i',
  18121. '�' => 'j',
  18122. '�' => 'k',
  18123. '�' => 'l',
  18124. '�' => 'm',
  18125. '�' => 'n',
  18126. '�' => 'o',
  18127. '�' => 'p',
  18128. '�' => 'q',
  18129. '�' => 'r',
  18130. '�' => 's',
  18131. '�' => 't',
  18132. '�' => 'u',
  18133. '�' => 'v',
  18134. '�' => 'w',
  18135. '�' => 'x',
  18136. '�' => 'y',
  18137. '�' => 'z',
  18138. '�' => 'A',
  18139. '�' => 'B',
  18140. '�' => 'C',
  18141. '�' => 'D',
  18142. '�' => 'E',
  18143. '�' => 'F',
  18144. '�' => 'G',
  18145. '�' => 'H',
  18146. '�' => 'I',
  18147. '�' => 'J',
  18148. '�' => 'K',
  18149. '�' => 'L',
  18150. '�' => 'M',
  18151. '�' => 'N',
  18152. '�' => 'O',
  18153. '�' => 'P',
  18154. '�' => 'Q',
  18155. '�' => 'R',
  18156. '�' => 'S',
  18157. '�' => 'T',
  18158. '�' => 'U',
  18159. '�' => 'V',
  18160. '�' => 'W',
  18161. '�' => 'X',
  18162. '�' => 'Y',
  18163. '�' => 'Z',
  18164. '�' => 'a',
  18165. '�' => 'b',
  18166. '�' => 'c',
  18167. '�' => 'd',
  18168. '�' => 'e',
  18169. '�' => 'f',
  18170. '�' => 'g',
  18171. '�' => 'h',
  18172. '�' => 'i',
  18173. '�' => 'j',
  18174. '�' => 'k',
  18175. '�' => 'l',
  18176. '�' => 'm',
  18177. '�' => 'n',
  18178. '�' => 'o',
  18179. '�' => 'p',
  18180. '�' => 'q',
  18181. '�' => 'r',
  18182. '�' => 's',
  18183. '�' => 't',
  18184. '�' => 'u',
  18185. '�' => 'v',
  18186. '�' => 'w',
  18187. '�' => 'x',
  18188. '�' => 'y',
  18189. '�' => 'z',
  18190. '�' => 'A',
  18191. '�' => 'B',
  18192. '�' => 'C',
  18193. '�' => 'D',
  18194. '�' => 'E',
  18195. '�' => 'F',
  18196. '�' => 'G',
  18197. '�' => 'H',
  18198. '�' => 'I',
  18199. '�' => 'J',
  18200. '�' => 'K',
  18201. '�' => 'L',
  18202. '�' => 'M',
  18203. '�' => 'N',
  18204. '�' => 'O',
  18205. '�' => 'P',
  18206. '�' => 'Q',
  18207. '�' => 'R',
  18208. '�' => 'S',
  18209. '�' => 'T',
  18210. '�' => 'U',
  18211. '�' => 'V',
  18212. '�' => 'W',
  18213. '�' => 'X',
  18214. '�' => 'Y',
  18215. '�' => 'Z',
  18216. '�' => 'a',
  18217. '�' => 'b',
  18218. '�' => 'c',
  18219. '�' => 'd',
  18220. '�' => 'e',
  18221. '�' => 'f',
  18222. '�' => 'g',
  18223. '�' => 'h',
  18224. '�' => 'i',
  18225. '�' => 'j',
  18226. '�' => 'k',
  18227. '�' => 'l',
  18228. '�' => 'm',
  18229. '�' => 'n',
  18230. '�' => 'o',
  18231. '�' => 'p',
  18232. '�' => 'q',
  18233. '�' => 'r',
  18234. '�' => 's',
  18235. '�' => 't',
  18236. '�' => 'u',
  18237. '�' => 'v',
  18238. '�' => 'w',
  18239. '�' => 'x',
  18240. '�' => 'y',
  18241. '�' => 'z',
  18242. '�' => 'A',
  18243. '�' => 'B',
  18244. '�' => 'C',
  18245. '�' => 'D',
  18246. '�' => 'E',
  18247. '�' => 'F',
  18248. '�' => 'G',
  18249. '�' => 'H',
  18250. '�' => 'I',
  18251. '�' => 'J',
  18252. '�' => 'K',
  18253. '�' => 'L',
  18254. '�' => 'M',
  18255. '�' => 'N',
  18256. '�' => 'O',
  18257. '�' => 'P',
  18258. '�' => 'Q',
  18259. '�' => 'R',
  18260. '�' => 'S',
  18261. '�' => 'T',
  18262. '�' => 'U',
  18263. '�' => 'V',
  18264. '�' => 'W',
  18265. '�' => 'X',
  18266. '�' => 'Y',
  18267. '�' => 'Z',
  18268. '�' => 'a',
  18269. '�' => 'b',
  18270. '�' => 'c',
  18271. '�' => 'd',
  18272. '�' => 'e',
  18273. '�' => 'f',
  18274. '�' => 'g',
  18275. '�' => 'h',
  18276. '�' => 'i',
  18277. '�' => 'j',
  18278. '�' => 'k',
  18279. '�' => 'l',
  18280. '�' => 'm',
  18281. '�' => 'n',
  18282. '�' => 'o',
  18283. '�' => 'p',
  18284. '�' => 'q',
  18285. '�' => 'r',
  18286. '�' => 's',
  18287. '�' => 't',
  18288. '�' => 'u',
  18289. '�' => 'v',
  18290. '�' => 'w',
  18291. '�' => 'x',
  18292. '�' => 'y',
  18293. '�' => 'z',
  18294. '�' => 'A',
  18295. '�' => 'B',
  18296. '�' => 'C',
  18297. '�' => 'D',
  18298. '�' => 'E',
  18299. '�' => 'F',
  18300. '�' => 'G',
  18301. '�' => 'H',
  18302. '�' => 'I',
  18303. '�' => 'J',
  18304. '�' => 'K',
  18305. '�' => 'L',
  18306. '�' => 'M',
  18307. '�' => 'N',
  18308. '�' => 'O',
  18309. '�' => 'P',
  18310. '�' => 'Q',
  18311. '�' => 'R',
  18312. '�' => 'S',
  18313. '�' => 'T',
  18314. '�' => 'U',
  18315. '�' => 'V',
  18316. '�' => 'W',
  18317. '�' => 'X',
  18318. '�' => 'Y',
  18319. '�' => 'Z',
  18320. '�' => 'a',
  18321. '�' => 'b',
  18322. '�' => 'c',
  18323. '�' => 'd',
  18324. '�' => 'e',
  18325. '�' => 'f',
  18326. '�' => 'g',
  18327. '�' => 'h',
  18328. '�' => 'i',
  18329. '�' => 'j',
  18330. '�' => 'k',
  18331. '�' => 'l',
  18332. '�' => 'm',
  18333. '�' => 'n',
  18334. '�' => 'o',
  18335. '�' => 'p',
  18336. '�' => 'q',
  18337. '�' => 'r',
  18338. '�' => 's',
  18339. '�' => 't',
  18340. '�' => 'u',
  18341. '�' => 'v',
  18342. '�' => 'w',
  18343. '�' => 'x',
  18344. '�' => 'y',
  18345. '�' => 'z',
  18346. '�' => 'ı',
  18347. '�' => 'ȷ',
  18348. '�' => 'Α',
  18349. '�' => 'Β',
  18350. '�' => 'Γ',
  18351. '�' => 'Δ',
  18352. '�' => 'Ε',
  18353. '�' => 'Ζ',
  18354. '�' => 'Η',
  18355. '�' => 'Θ',
  18356. '�' => 'Ι',
  18357. '�' => 'Κ',
  18358. '�' => 'Λ',
  18359. '�' => 'Μ',
  18360. '�' => '�',
  18361. '�' => 'Ξ',
  18362. '�' => 'Ο',
  18363. '�' => 'Π',
  18364. '�' => 'Ρ',
  18365. '�' => 'Θ',
  18366. '�' => 'Σ',
  18367. '�' => 'Τ',
  18368. '�' => 'Υ',
  18369. '�' => 'Φ',
  18370. '�' => 'Χ',
  18371. '�' => 'Ψ',
  18372. '�' => 'Ω',
  18373. '�' => '∇',
  18374. '�' => 'α',
  18375. '�' => 'β',
  18376. '�' => 'γ',
  18377. '�' => 'δ',
  18378. '�' => 'ε',
  18379. '�' => 'ζ',
  18380. '�' => 'η',
  18381. '�' => 'θ',
  18382. '�' => 'ι',
  18383. '�' => 'κ',
  18384. '�' => 'λ',
  18385. '�' => 'μ',
  18386. '�' => 'ν',
  18387. '�' => 'ξ',
  18388. '�' => 'ο',
  18389. '�' => 'π',
  18390. '�' => '�',
  18391. '�' => 'ς',
  18392. '�' => 'σ',
  18393. '�' => 'τ',
  18394. '�' => 'υ',
  18395. '�' => 'φ',
  18396. '�' => 'χ',
  18397. '�' => 'ψ',
  18398. '�' => 'ω',
  18399. '�' => '∂',
  18400. '�' => 'ε',
  18401. '�' => 'θ',
  18402. '�' => 'κ',
  18403. '�' => 'φ',
  18404. '�' => '�',
  18405. '�' => 'π',
  18406. '�' => 'Α',
  18407. '�' => 'Β',
  18408. '�' => 'Γ',
  18409. '�' => 'Δ',
  18410. '�' => 'Ε',
  18411. '�' => 'Ζ',
  18412. '�' => 'Η',
  18413. '�' => 'Θ',
  18414. '�' => 'Ι',
  18415. '�' => 'Κ',
  18416. '�' => 'Λ',
  18417. '�' => 'Μ',
  18418. '�' => '�',
  18419. '�' => 'Ξ',
  18420. '�' => 'Ο',
  18421. '�' => 'Π',
  18422. '�' => 'Ρ',
  18423. '�' => 'Θ',
  18424. '�' => 'Σ',
  18425. '�' => 'Τ',
  18426. '�' => 'Υ',
  18427. '�' => 'Φ',
  18428. '�' => 'Χ',
  18429. '�' => 'Ψ',
  18430. '�' => 'Ω',
  18431. '�' => '∇',
  18432. '�' => 'α',
  18433. '�' => 'β',
  18434. '�' => 'γ',
  18435. '�' => 'δ',
  18436. '�' => 'ε',
  18437. '�' => 'ζ',
  18438. '�' => 'η',
  18439. '�' => 'θ',
  18440. '�' => 'ι',
  18441. '�' => 'κ',
  18442. '�' => 'λ',
  18443. '�' => 'μ',
  18444. '�' => 'ν',
  18445. '�' => 'ξ',
  18446. '�' => 'ο',
  18447. '�' => 'π',
  18448. '�' => '�',
  18449. '�' => 'ς',
  18450. '�' => 'σ',
  18451. '�' => 'τ',
  18452. '�' => 'υ',
  18453. '�' => 'φ',
  18454. '�' => 'χ',
  18455. '�' => 'ψ',
  18456. '�' => 'ω',
  18457. '�' => '∂',
  18458. '�' => 'ε',
  18459. '�' => 'θ',
  18460. '�' => 'κ',
  18461. '�' => 'φ',
  18462. '�' => '�',
  18463. '�' => 'π',
  18464. '�' => 'Α',
  18465. '�' => 'Β',
  18466. '�' => 'Γ',
  18467. '�' => 'Δ',
  18468. '�' => 'Ε',
  18469. '�' => 'Ζ',
  18470. '�' => 'Η',
  18471. '�' => 'Θ',
  18472. '�' => 'Ι',
  18473. '�' => 'Κ',
  18474. '�' => 'Λ',
  18475. '�' => 'Μ',
  18476. '�' => '�',
  18477. '�' => 'Ξ',
  18478. '�' => 'Ο',
  18479. '�' => 'Π',
  18480. '�' => 'Ρ',
  18481. '�' => 'Θ',
  18482. '�' => 'Σ',
  18483. '�' => 'Τ',
  18484. '�' => 'Υ',
  18485. '�' => 'Φ',
  18486. '�' => 'Χ',
  18487. '�' => 'Ψ',
  18488. '�' => 'Ω',
  18489. '�' => '∇',
  18490. '�' => 'α',
  18491. '�' => 'β',
  18492. '�' => 'γ',
  18493. '�' => 'δ',
  18494. '�' => 'ε',
  18495. '�' => 'ζ',
  18496. '�' => 'η',
  18497. '�' => 'θ',
  18498. '�' => 'ι',
  18499. '�' => 'κ',
  18500. '�' => 'λ',
  18501. '�' => 'μ',
  18502. '�' => 'ν',
  18503. '�' => 'ξ',
  18504. '�' => 'ο',
  18505. '�' => 'π',
  18506. '�' => '�',
  18507. '�' => 'ς',
  18508. '�' => 'σ',
  18509. '�' => 'τ',
  18510. '�' => 'υ',
  18511. '�' => 'φ',
  18512. '�' => 'χ',
  18513. '�' => 'ψ',
  18514. '�' => 'ω',
  18515. '�' => '∂',
  18516. '�' => 'ε',
  18517. '�' => 'θ',
  18518. '�' => 'κ',
  18519. '�' => 'φ',
  18520. '�' => '�',
  18521. '�' => 'π',
  18522. '�' => 'Α',
  18523. '�' => 'Β',
  18524. '�' => 'Γ',
  18525. '�' => 'Δ',
  18526. '�' => 'Ε',
  18527. '�' => 'Ζ',
  18528. '�' => 'Η',
  18529. '�' => 'Θ',
  18530. '�' => 'Ι',
  18531. '�' => 'Κ',
  18532. '�' => 'Λ',
  18533. '�' => 'Μ',
  18534. '�' => '�',
  18535. '�' => 'Ξ',
  18536. '�' => 'Ο',
  18537. '�' => 'Π',
  18538. '�' => 'Ρ',
  18539. '�' => 'Θ',
  18540. '�' => 'Σ',
  18541. '�' => 'Τ',
  18542. '�' => 'Υ',
  18543. '�' => 'Φ',
  18544. '�' => 'Χ',
  18545. '�' => 'Ψ',
  18546. '�' => 'Ω',
  18547. '�' => '∇',
  18548. '�' => 'α',
  18549. '�' => 'β',
  18550. '�' => 'γ',
  18551. '�' => 'δ',
  18552. '�' => 'ε',
  18553. '�' => 'ζ',
  18554. '�' => 'η',
  18555. '�' => 'θ',
  18556. '�' => 'ι',
  18557. '�' => 'κ',
  18558. '�' => 'λ',
  18559. '�' => 'μ',
  18560. '�' => 'ν',
  18561. '�' => 'ξ',
  18562. '�' => 'ο',
  18563. '�' => 'π',
  18564. '�' => '�',
  18565. '�' => 'ς',
  18566. '�' => 'σ',
  18567. '�' => 'τ',
  18568. '�' => 'υ',
  18569. '�' => 'φ',
  18570. '�' => 'χ',
  18571. '�' => 'ψ',
  18572. '�' => 'ω',
  18573. '�' => '∂',
  18574. '�' => 'ε',
  18575. '�' => 'θ',
  18576. '�' => 'κ',
  18577. '�' => 'φ',
  18578. '�' => '�',
  18579. '�' => 'π',
  18580. '�' => 'Α',
  18581. '�' => 'Β',
  18582. '�' => 'Γ',
  18583. '�' => 'Δ',
  18584. '�' => 'Ε',
  18585. '�' => 'Ζ',
  18586. '�' => 'Η',
  18587. '�' => 'Θ',
  18588. '�' => 'Ι',
  18589. '�' => 'Κ',
  18590. '�' => 'Λ',
  18591. '�' => 'Μ',
  18592. '�' => '�',
  18593. '�' => 'Ξ',
  18594. '�' => 'Ο',
  18595. '�' => 'Π',
  18596. '�' => 'Ρ',
  18597. '�' => 'Θ',
  18598. '�' => 'Σ',
  18599. '�' => 'Τ',
  18600. '�' => 'Υ',
  18601. '�' => 'Φ',
  18602. '�' => 'Χ',
  18603. '�' => 'Ψ',
  18604. '�' => 'Ω',
  18605. '�' => '∇',
  18606. '�' => 'α',
  18607. '�' => 'β',
  18608. '�' => 'γ',
  18609. '�' => 'δ',
  18610. '�' => 'ε',
  18611. '�' => 'ζ',
  18612. '�' => 'η',
  18613. '�' => 'θ',
  18614. '�' => 'ι',
  18615. '�' => 'κ',
  18616. '�' => 'λ',
  18617. '�' => 'μ',
  18618. '�' => 'ν',
  18619. '�' => 'ξ',
  18620. '�' => 'ο',
  18621. '�' => 'π',
  18622. '�' => '�',
  18623. '�' => 'ς',
  18624. '�' => 'σ',
  18625. '�' => 'τ',
  18626. '�' => 'υ',
  18627. '�' => 'φ',
  18628. '�' => 'χ',
  18629. '�' => 'ψ',
  18630. '�' => 'ω',
  18631. '�' => '∂',
  18632. '�' => 'ε',
  18633. '�' => 'θ',
  18634. '�' => 'κ',
  18635. '�' => 'φ',
  18636. '�' => '�',
  18637. '�' => 'π',
  18638. '�' => 'Ϝ',
  18639. '�' => '�',
  18640. '�' => '0',
  18641. '�' => '1',
  18642. '�' => '2',
  18643. '�' => '3',
  18644. '�' => '4',
  18645. '�' => '5',
  18646. '�' => '6',
  18647. '�' => '7',
  18648. '�' => '8',
  18649. '�' => '9',
  18650. '�' => '0',
  18651. '�' => '1',
  18652. '�' => '2',
  18653. '�' => '3',
  18654. '�' => '4',
  18655. '�' => '5',
  18656. '�' => '6',
  18657. '�' => '7',
  18658. '�' => '8',
  18659. '�' => '9',
  18660. '�' => '0',
  18661. '�' => '1',
  18662. '�' => '2',
  18663. '�' => '3',
  18664. '�' => '4',
  18665. '�' => '5',
  18666. '�' => '6',
  18667. '�' => '7',
  18668. '�' => '8',
  18669. '�' => '9',
  18670. '�' => '0',
  18671. '�' => '1',
  18672. '�' => '2',
  18673. '�' => '3',
  18674. '�' => '4',
  18675. '�' => '5',
  18676. '�' => '6',
  18677. '�' => '7',
  18678. '�' => '8',
  18679. '�' => '9',
  18680. '�' => '0',
  18681. '�' => '1',
  18682. '�' => '2',
  18683. '�' => '3',
  18684. '�' => '4',
  18685. '�' => '5',
  18686. '�' => '6',
  18687. '�' => '7',
  18688. '�' => '8',
  18689. '�' => '9',
  18690. '𞸀' => 'ا',
  18691. '�' => 'ب',
  18692. '𞸂' => 'ج',
  18693. '𞸃' => 'د',
  18694. '𞸅' => 'و',
  18695. '𞸆' => 'ز',
  18696. '𞸇' => 'ح',
  18697. '𞸈' => 'ط',
  18698. '𞸉' => 'ي',
  18699. '𞸊' => 'ك',
  18700. '𞸋' => 'ل',
  18701. '𞸌' => 'م',
  18702. '�' => 'ن',
  18703. '𞸎' => 'س',
  18704. '�' => 'ع',
  18705. '�' => '�',
  18706. '𞸑' => 'ص',
  18707. '𞸒' => 'ق',
  18708. '𞸓' => 'ر',
  18709. '𞸔' => 'ش',
  18710. '𞸕' => 'ت',
  18711. '𞸖' => 'ث',
  18712. '𞸗' => 'خ',
  18713. '𞸘' => 'ذ',
  18714. '𞸙' => 'ض',
  18715. '𞸚' => 'ظ',
  18716. '𞸛' => 'غ',
  18717. '𞸜' => 'ٮ',
  18718. '�' => 'ں',
  18719. '𞸞' => 'ڡ',
  18720. '𞸟' => 'ٯ',
  18721. '𞸡' => 'ب',
  18722. '𞸢' => 'ج',
  18723. '𞸤' => 'ه',
  18724. '𞸧' => 'ح',
  18725. '𞸩' => 'ي',
  18726. '𞸪' => 'ك',
  18727. '𞸫' => 'ل',
  18728. '𞸬' => 'م',
  18729. '𞸭' => 'ن',
  18730. '𞸮' => 'س',
  18731. '𞸯' => 'ع',
  18732. '𞸰' => '�',
  18733. '𞸱' => 'ص',
  18734. '𞸲' => 'ق',
  18735. '𞸴' => 'ش',
  18736. '𞸵' => 'ت',
  18737. '𞸶' => 'ث',
  18738. '𞸷' => 'خ',
  18739. '𞸹' => 'ض',
  18740. '𞸻' => 'غ',
  18741. '𞹂' => 'ج',
  18742. '𞹇' => 'ح',
  18743. '𞹉' => 'ي',
  18744. '𞹋' => 'ل',
  18745. '�' => 'ن',
  18746. '𞹎' => 'س',
  18747. '�' => 'ع',
  18748. '𞹑' => 'ص',
  18749. 'ðž¹’' => 'Ù‚',
  18750. 'ðž¹”' => 'Ø´',
  18751. 'ðž¹—' => 'Ø®',
  18752. '𞹙' => 'ض',
  18753. '𞹛' => 'غ',
  18754. '�' => 'ں',
  18755. '𞹟' => 'ٯ',
  18756. '𞹡' => 'ب',
  18757. '𞹢' => 'ج',
  18758. '𞹤' => 'ه',
  18759. 'ðž¹§' => 'Ø­',
  18760. '𞹨' => 'ط',
  18761. '𞹩' => 'ي',
  18762. '𞹪' => 'ك',
  18763. '𞹬' => 'م',
  18764. 'ðž¹­' => 'Ù†',
  18765. '𞹮' => 'س',
  18766. '𞹯' => 'ع',
  18767. 'ðž¹°' => 'Ù�',
  18768. '𞹱' => 'ص',
  18769. 'ðž¹²' => 'Ù‚',
  18770. 'ðž¹´' => 'Ø´',
  18771. '𞹵' => 'ت',
  18772. 'ðž¹¶' => 'Ø«',
  18773. 'ðž¹·' => 'Ø®',
  18774. '𞹹' => 'ض',
  18775. '𞹺' => 'ظ',
  18776. '𞹻' => 'غ',
  18777. 'ðž¹¼' => 'Ù®',
  18778. 'ðž¹¾' => 'Ú¡',
  18779. '𞺀' => 'ا',
  18780. '�' => 'ب',
  18781. '𞺂' => 'ج',
  18782. '𞺃' => 'د',
  18783. '𞺄' => 'ه',
  18784. '𞺅' => 'و',
  18785. '𞺆' => 'ز',
  18786. '𞺇' => 'ح',
  18787. '𞺈' => 'ط',
  18788. '𞺉' => 'ي',
  18789. '𞺋' => 'ل',
  18790. '𞺌' => 'م',
  18791. '�' => 'ن',
  18792. '𞺎' => 'س',
  18793. '�' => 'ع',
  18794. '�' => '�',
  18795. '𞺑' => 'ص',
  18796. '𞺒' => 'ق',
  18797. '𞺓' => 'ر',
  18798. '𞺔' => 'ش',
  18799. '𞺕' => 'ت',
  18800. '𞺖' => 'ث',
  18801. '𞺗' => 'خ',
  18802. '𞺘' => 'ذ',
  18803. '𞺙' => 'ض',
  18804. '𞺚' => 'ظ',
  18805. '𞺛' => 'غ',
  18806. '𞺡' => 'ب',
  18807. '𞺢' => 'ج',
  18808. '𞺣' => 'د',
  18809. '𞺥' => 'و',
  18810. '𞺦' => 'ز',
  18811. '𞺧' => 'ح',
  18812. '𞺨' => 'ط',
  18813. '𞺩' => 'ي',
  18814. '𞺫' => 'ل',
  18815. '𞺬' => 'م',
  18816. '𞺭' => 'ن',
  18817. '𞺮' => 'س',
  18818. '𞺯' => 'ع',
  18819. '𞺰' => '�',
  18820. '𞺱' => 'ص',
  18821. '𞺲' => 'ق',
  18822. '𞺳' => 'ر',
  18823. '𞺴' => 'ش',
  18824. '𞺵' => 'ت',
  18825. '𞺶' => 'ث',
  18826. '𞺷' => 'خ',
  18827. '𞺸' => 'ذ',
  18828. '𞺹' => 'ض',
  18829. '𞺺' => 'ظ',
  18830. '𞺻' => 'غ',
  18831. '🄀' => '0.',
  18832. '�' => '0,',
  18833. '🄂' => '1,',
  18834. '🄃' => '2,',
  18835. '🄄' => '3,',
  18836. '🄅' => '4,',
  18837. '🄆' => '5,',
  18838. '🄇' => '6,',
  18839. '🄈' => '7,',
  18840. '🄉' => '8,',
  18841. '🄊' => '9,',
  18842. '�' => '(A)',
  18843. '🄑' => '(B)',
  18844. '🄒' => '(C)',
  18845. '🄓' => '(D)',
  18846. '🄔' => '(E)',
  18847. '🄕' => '(F)',
  18848. '🄖' => '(G)',
  18849. '🄗' => '(H)',
  18850. '🄘' => '(I)',
  18851. '🄙' => '(J)',
  18852. '🄚' => '(K)',
  18853. '🄛' => '(L)',
  18854. '🄜' => '(M)',
  18855. '�' => '(N)',
  18856. '🄞' => '(O)',
  18857. '🄟' => '(P)',
  18858. '🄠' => '(Q)',
  18859. '🄡' => '(R)',
  18860. '🄢' => '(S)',
  18861. '🄣' => '(T)',
  18862. '🄤' => '(U)',
  18863. '🄥' => '(V)',
  18864. '🄦' => '(W)',
  18865. '🄧' => '(X)',
  18866. '🄨' => '(Y)',
  18867. '🄩' => '(Z)',
  18868. '🄪' => '〔S〕',
  18869. '🄫' => 'C',
  18870. '🄬' => 'R',
  18871. '🄭' => 'CD',
  18872. '🄮' => 'WZ',
  18873. '🄰' => 'A',
  18874. '🄱' => 'B',
  18875. '🄲' => 'C',
  18876. '🄳' => 'D',
  18877. '🄴' => 'E',
  18878. '🄵' => 'F',
  18879. '🄶' => 'G',
  18880. '🄷' => 'H',
  18881. '🄸' => 'I',
  18882. '🄹' => 'J',
  18883. '🄺' => 'K',
  18884. '🄻' => 'L',
  18885. '🄼' => 'M',
  18886. '🄽' => 'N',
  18887. '🄾' => 'O',
  18888. '🄿' => 'P',
  18889. '🅀' => 'Q',
  18890. '�' => 'R',
  18891. '🅂' => 'S',
  18892. '🅃' => 'T',
  18893. '🅄' => 'U',
  18894. '🅅' => 'V',
  18895. '🅆' => 'W',
  18896. '🅇' => 'X',
  18897. '🅈' => 'Y',
  18898. '🅉' => 'Z',
  18899. '🅊' => 'HV',
  18900. '🅋' => 'MV',
  18901. '🅌' => 'SD',
  18902. '�' => 'SS',
  18903. '🅎' => 'PPV',
  18904. '�' => 'WC',
  18905. '🅪' => 'MC',
  18906. '🅫' => 'MD',
  18907. '🅬' => 'MR',
  18908. '�' => 'DJ',
  18909. '🈀' => '��',
  18910. '�' => 'ココ',
  18911. '🈂' => 'サ',
  18912. '�' => '手',
  18913. '🈑' => '字',
  18914. '🈒' => '�',
  18915. '🈓' => 'デ',
  18916. '🈔' => '二',
  18917. '🈕' => '多',
  18918. '🈖' => '解',
  18919. '🈗' => '天',
  18920. '🈘' => '交',
  18921. '🈙' => '映',
  18922. '🈚' => '無',
  18923. '🈛' => '料',
  18924. '🈜' => '�',
  18925. '�' => '後',
  18926. '🈞' => '�',
  18927. '🈟' => '新',
  18928. '🈠' => '�',
  18929. '🈡' => '終',
  18930. '🈢' => '生',
  18931. '🈣' => '販',
  18932. '🈤' => '声',
  18933. '🈥' => '�',
  18934. '🈦' => '演',
  18935. '🈧' => '投',
  18936. '🈨' => '�',
  18937. '🈩' => '一',
  18938. '🈪' => '三',
  18939. '🈫' => '�',
  18940. '🈬' => '左',
  18941. '🈭' => '中',
  18942. '🈮' => '�',
  18943. '🈯' => '指',
  18944. '🈰' => '走',
  18945. '🈱' => '打',
  18946. '🈲' => '�',
  18947. '🈳' => '空',
  18948. '🈴' => '�',
  18949. '🈵' => '満',
  18950. '🈶' => '有',
  18951. '🈷' => '月',
  18952. '🈸' => '申',
  18953. '🈹' => '割',
  18954. '🈺' => '営',
  18955. '🈻' => '�',
  18956. '🉀' => '〔本〕',
  18957. '�' => '〔三〕',
  18958. '🉂' => '〔二〕',
  18959. '🉃' => '〔安〕',
  18960. '🉄' => '〔点〕',
  18961. '🉅' => '〔打〕',
  18962. '🉆' => '〔盗〕',
  18963. '🉇' => '〔�〕',
  18964. '🉈' => '〔敗〕',
  18965. '�' => '得',
  18966. '🉑' => '�',
  18967. '🯰' => '0',
  18968. '🯱' => '1',
  18969. '🯲' => '2',
  18970. '🯳' => '3',
  18971. '🯴' => '4',
  18972. '🯵' => '5',
  18973. '🯶' => '6',
  18974. '🯷' => '7',
  18975. '🯸' => '8',
  18976. '🯹' => '9',
  18977. );
  18978. <?php
  18979. use Symfony\Polyfill\Intl\Normalizer as p;
  18980. if (\PHP_VERSION_ID >= 80000) {
  18981. return require __DIR__.'/bootstrap80.php';
  18982. }
  18983. if (!function_exists('normalizer_is_normalized')) {
  18984. function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); }
  18985. }
  18986. if (!function_exists('normalizer_normalize')) {
  18987. function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); }
  18988. }
  18989. <?php
  18990. namespace Symfony\Contracts\EventDispatcher;
  18991. use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
  18992. interface EventDispatcherInterface extends PsrEventDispatcherInterface
  18993. {
  18994. public function dispatch(object $event, ?string $eventName = null): object;
  18995. }
  18996. <?php
  18997. namespace Symfony\Contracts\EventDispatcher;
  18998. use Psr\EventDispatcher\StoppableEventInterface;
  18999. class Event implements StoppableEventInterface
  19000. {
  19001. private $propagationStopped = false;
  19002. public function isPropagationStopped(): bool
  19003. {
  19004. return $this->propagationStopped;
  19005. }
  19006. public function stopPropagation(): void
  19007. {
  19008. $this->propagationStopped = true;
  19009. }
  19010. }
  19011. <?php
  19012. namespace Symfony\Component\Finder;
  19013. class SplFileInfo extends \SplFileInfo
  19014. {
  19015. private $relativePath;
  19016. private $relativePathname;
  19017. public function __construct(string $file, string $relativePath, string $relativePathname)
  19018. {
  19019. parent::__construct($file);
  19020. $this->relativePath = $relativePath;
  19021. $this->relativePathname = $relativePathname;
  19022. }
  19023. public function getRelativePath()
  19024. {
  19025. return $this->relativePath;
  19026. }
  19027. public function getRelativePathname()
  19028. {
  19029. return $this->relativePathname;
  19030. }
  19031. public function getFilenameWithoutExtension(): string
  19032. {
  19033. $filename = $this->getFilename();
  19034. return pathinfo($filename, \PATHINFO_FILENAME);
  19035. }
  19036. public function getContents()
  19037. {
  19038. set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
  19039. try {
  19040. $content = file_get_contents($this->getPathname());
  19041. } finally {
  19042. restore_error_handler();
  19043. }
  19044. if (false === $content) {
  19045. throw new \RuntimeException($error);
  19046. }
  19047. return $content;
  19048. }
  19049. }
  19050. <?php
  19051. namespace Symfony\Component\Finder\Comparator;
  19052. class NumberComparator extends Comparator
  19053. {
  19054. public function __construct(?string $test)
  19055. {
  19056. if (null === $test || !preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
  19057. throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null'));
  19058. }
  19059. $target = $matches[2];
  19060. if (!is_numeric($target)) {
  19061. throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
  19062. }
  19063. if (isset($matches[3])) {
  19064. switch (strtolower($matches[3])) {
  19065. case 'k':
  19066. $target *= 1000;
  19067. break;
  19068. case 'ki':
  19069. $target *= 1024;
  19070. break;
  19071. case 'm':
  19072. $target *= 1000000;
  19073. break;
  19074. case 'mi':
  19075. $target *= 1024 * 1024;
  19076. break;
  19077. case 'g':
  19078. $target *= 1000000000;
  19079. break;
  19080. case 'gi':
  19081. $target *= 1024 * 1024 * 1024;
  19082. break;
  19083. }
  19084. }
  19085. parent::__construct($target, $matches[1] ?: '==');
  19086. }
  19087. }
  19088. <?php
  19089. namespace Symfony\Component\Finder\Comparator;
  19090. class Comparator
  19091. {
  19092. private $target;
  19093. private $operator = '==';
  19094. public function __construct(?string $target = null, string $operator = '==')
  19095. {
  19096. if (null === $target) {
  19097. trigger_deprecation('symfony/finder', '5.4', 'Constructing a "%s" without setting "$target" is deprecated.', __CLASS__);
  19098. }
  19099. $this->target = $target;
  19100. $this->doSetOperator($operator);
  19101. }
  19102. public function getTarget()
  19103. {
  19104. if (null === $this->target) {
  19105. trigger_deprecation('symfony/finder', '5.4', 'Calling "%s" without initializing the target is deprecated.', __METHOD__);
  19106. }
  19107. return $this->target;
  19108. }
  19109. public function setTarget(string $target)
  19110. {
  19111. trigger_deprecation('symfony/finder', '5.4', '"%s" is deprecated. Set the target via the constructor instead.', __METHOD__);
  19112. $this->target = $target;
  19113. }
  19114. public function getOperator()
  19115. {
  19116. return $this->operator;
  19117. }
  19118. public function setOperator(string $operator)
  19119. {
  19120. trigger_deprecation('symfony/finder', '5.4', '"%s" is deprecated. Set the operator via the constructor instead.', __METHOD__);
  19121. $this->doSetOperator('' === $operator ? '==' : $operator);
  19122. }
  19123. public function test($test)
  19124. {
  19125. if (null === $this->target) {
  19126. trigger_deprecation('symfony/finder', '5.4', 'Calling "%s" without initializing the target is deprecated.', __METHOD__);
  19127. }
  19128. switch ($this->operator) {
  19129. case '>':
  19130. return $test > $this->target;
  19131. case '>=':
  19132. return $test >= $this->target;
  19133. case '<':
  19134. return $test < $this->target;
  19135. case '<=':
  19136. return $test <= $this->target;
  19137. case '!=':
  19138. return $test != $this->target;
  19139. }
  19140. return $test == $this->target;
  19141. }
  19142. private function doSetOperator(string $operator): void
  19143. {
  19144. if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
  19145. throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
  19146. }
  19147. $this->operator = $operator;
  19148. }
  19149. }
  19150. <?php
  19151. namespace Symfony\Component\Finder\Comparator;
  19152. class DateComparator extends Comparator
  19153. {
  19154. public function __construct(string $test)
  19155. {
  19156. if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
  19157. throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
  19158. }
  19159. try {
  19160. $date = new \DateTime($matches[2]);
  19161. $target = $date->format('U');
  19162. } catch (\Exception $e) {
  19163. throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
  19164. }
  19165. $operator = $matches[1] ?? '==';
  19166. if ('since' === $operator || 'after' === $operator) {
  19167. $operator = '>';
  19168. }
  19169. if ('until' === $operator || 'before' === $operator) {
  19170. $operator = '<';
  19171. }
  19172. parent::__construct($target, $operator);
  19173. }
  19174. }
  19175. <?php
  19176. namespace Symfony\Component\Finder;
  19177. use Symfony\Component\Finder\Comparator\DateComparator;
  19178. use Symfony\Component\Finder\Comparator\NumberComparator;
  19179. use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
  19180. use Symfony\Component\Finder\Iterator\CustomFilterIterator;
  19181. use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
  19182. use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
  19183. use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
  19184. use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
  19185. use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
  19186. use Symfony\Component\Finder\Iterator\LazyIterator;
  19187. use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
  19188. use Symfony\Component\Finder\Iterator\SortableIterator;
  19189. /**
  19190. @implements
  19191. */
  19192. class Finder implements \IteratorAggregate, \Countable
  19193. {
  19194. public const IGNORE_VCS_FILES = 1;
  19195. public const IGNORE_DOT_FILES = 2;
  19196. public const IGNORE_VCS_IGNORED_FILES = 4;
  19197. private $mode = 0;
  19198. private $names = [];
  19199. private $notNames = [];
  19200. private $exclude = [];
  19201. private $filters = [];
  19202. private $depths = [];
  19203. private $sizes = [];
  19204. private $followLinks = false;
  19205. private $reverseSorting = false;
  19206. private $sort = false;
  19207. private $ignore = 0;
  19208. private $dirs = [];
  19209. private $dates = [];
  19210. private $iterators = [];
  19211. private $contains = [];
  19212. private $notContains = [];
  19213. private $paths = [];
  19214. private $notPaths = [];
  19215. private $ignoreUnreadableDirs = false;
  19216. private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
  19217. public function __construct()
  19218. {
  19219. $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
  19220. }
  19221. public static function create()
  19222. {
  19223. return new static();
  19224. }
  19225. public function directories()
  19226. {
  19227. $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
  19228. return $this;
  19229. }
  19230. public function files()
  19231. {
  19232. $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
  19233. return $this;
  19234. }
  19235. public function depth($levels)
  19236. {
  19237. foreach ((array) $levels as $level) {
  19238. $this->depths[] = new Comparator\NumberComparator($level);
  19239. }
  19240. return $this;
  19241. }
  19242. public function date($dates)
  19243. {
  19244. foreach ((array) $dates as $date) {
  19245. $this->dates[] = new Comparator\DateComparator($date);
  19246. }
  19247. return $this;
  19248. }
  19249. public function name($patterns)
  19250. {
  19251. $this->names = array_merge($this->names, (array) $patterns);
  19252. return $this;
  19253. }
  19254. public function notName($patterns)
  19255. {
  19256. $this->notNames = array_merge($this->notNames, (array) $patterns);
  19257. return $this;
  19258. }
  19259. public function contains($patterns)
  19260. {
  19261. $this->contains = array_merge($this->contains, (array) $patterns);
  19262. return $this;
  19263. }
  19264. public function notContains($patterns)
  19265. {
  19266. $this->notContains = array_merge($this->notContains, (array) $patterns);
  19267. return $this;
  19268. }
  19269. public function path($patterns)
  19270. {
  19271. $this->paths = array_merge($this->paths, (array) $patterns);
  19272. return $this;
  19273. }
  19274. public function notPath($patterns)
  19275. {
  19276. $this->notPaths = array_merge($this->notPaths, (array) $patterns);
  19277. return $this;
  19278. }
  19279. public function size($sizes)
  19280. {
  19281. foreach ((array) $sizes as $size) {
  19282. $this->sizes[] = new Comparator\NumberComparator($size);
  19283. }
  19284. return $this;
  19285. }
  19286. public function exclude($dirs)
  19287. {
  19288. $this->exclude = array_merge($this->exclude, (array) $dirs);
  19289. return $this;
  19290. }
  19291. public function ignoreDotFiles(bool $ignoreDotFiles)
  19292. {
  19293. if ($ignoreDotFiles) {
  19294. $this->ignore |= static::IGNORE_DOT_FILES;
  19295. } else {
  19296. $this->ignore &= ~static::IGNORE_DOT_FILES;
  19297. }
  19298. return $this;
  19299. }
  19300. public function ignoreVCS(bool $ignoreVCS)
  19301. {
  19302. if ($ignoreVCS) {
  19303. $this->ignore |= static::IGNORE_VCS_FILES;
  19304. } else {
  19305. $this->ignore &= ~static::IGNORE_VCS_FILES;
  19306. }
  19307. return $this;
  19308. }
  19309. public function ignoreVCSIgnored(bool $ignoreVCSIgnored)
  19310. {
  19311. if ($ignoreVCSIgnored) {
  19312. $this->ignore |= static::IGNORE_VCS_IGNORED_FILES;
  19313. } else {
  19314. $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES;
  19315. }
  19316. return $this;
  19317. }
  19318. public static function addVCSPattern($pattern)
  19319. {
  19320. foreach ((array) $pattern as $p) {
  19321. self::$vcsPatterns[] = $p;
  19322. }
  19323. self::$vcsPatterns = array_unique(self::$vcsPatterns);
  19324. }
  19325. public function sort(\Closure $closure)
  19326. {
  19327. $this->sort = $closure;
  19328. return $this;
  19329. }
  19330. public function sortByName(bool $useNaturalSort = false)
  19331. {
  19332. $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME;
  19333. return $this;
  19334. }
  19335. public function sortByType()
  19336. {
  19337. $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
  19338. return $this;
  19339. }
  19340. public function sortByAccessedTime()
  19341. {
  19342. $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
  19343. return $this;
  19344. }
  19345. public function reverseSorting()
  19346. {
  19347. $this->reverseSorting = true;
  19348. return $this;
  19349. }
  19350. public function sortByChangedTime()
  19351. {
  19352. $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
  19353. return $this;
  19354. }
  19355. public function sortByModifiedTime()
  19356. {
  19357. $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
  19358. return $this;
  19359. }
  19360. public function filter(\Closure $closure)
  19361. {
  19362. $this->filters[] = $closure;
  19363. return $this;
  19364. }
  19365. public function followLinks()
  19366. {
  19367. $this->followLinks = true;
  19368. return $this;
  19369. }
  19370. public function ignoreUnreadableDirs(bool $ignore = true)
  19371. {
  19372. $this->ignoreUnreadableDirs = $ignore;
  19373. return $this;
  19374. }
  19375. public function in($dirs)
  19376. {
  19377. $resolvedDirs = [];
  19378. foreach ((array) $dirs as $dir) {
  19379. if (is_dir($dir)) {
  19380. $resolvedDirs[] = [$this->normalizeDir($dir)];
  19381. } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) {
  19382. sort($glob);
  19383. $resolvedDirs[] = array_map([$this, 'normalizeDir'], $glob);
  19384. } else {
  19385. throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
  19386. }
  19387. }
  19388. $this->dirs = array_merge($this->dirs, ...$resolvedDirs);
  19389. return $this;
  19390. }
  19391. #[\ReturnTypeWillChange]
  19392. public function getIterator()
  19393. {
  19394. if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
  19395. throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
  19396. }
  19397. if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
  19398. $iterator = $this->searchInDirectory($this->dirs[0]);
  19399. if ($this->sort || $this->reverseSorting) {
  19400. $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();
  19401. }
  19402. return $iterator;
  19403. }
  19404. $iterator = new \AppendIterator();
  19405. foreach ($this->dirs as $dir) {
  19406. $iterator->append(new \IteratorIterator(new LazyIterator(function () use ($dir) {
  19407. return $this->searchInDirectory($dir);
  19408. })));
  19409. }
  19410. foreach ($this->iterators as $it) {
  19411. $iterator->append($it);
  19412. }
  19413. if ($this->sort || $this->reverseSorting) {
  19414. $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();
  19415. }
  19416. return $iterator;
  19417. }
  19418. public function append(iterable $iterator)
  19419. {
  19420. if ($iterator instanceof \IteratorAggregate) {
  19421. $this->iterators[] = $iterator->getIterator();
  19422. } elseif ($iterator instanceof \Iterator) {
  19423. $this->iterators[] = $iterator;
  19424. } elseif (is_iterable($iterator)) {
  19425. $it = new \ArrayIterator();
  19426. foreach ($iterator as $file) {
  19427. $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file);
  19428. $it[$file->getPathname()] = $file;
  19429. }
  19430. $this->iterators[] = $it;
  19431. } else {
  19432. throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
  19433. }
  19434. return $this;
  19435. }
  19436. public function hasResults()
  19437. {
  19438. foreach ($this->getIterator() as $_) {
  19439. return true;
  19440. }
  19441. return false;
  19442. }
  19443. #[\ReturnTypeWillChange]
  19444. public function count()
  19445. {
  19446. return iterator_count($this->getIterator());
  19447. }
  19448. private function searchInDirectory(string $dir): \Iterator
  19449. {
  19450. $exclude = $this->exclude;
  19451. $notPaths = $this->notPaths;
  19452. if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
  19453. $exclude = array_merge($exclude, self::$vcsPatterns);
  19454. }
  19455. if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
  19456. $notPaths[] = '#(^|/)\..+(/|$)#';
  19457. }
  19458. $minDepth = 0;
  19459. $maxDepth = \PHP_INT_MAX;
  19460. foreach ($this->depths as $comparator) {
  19461. switch ($comparator->getOperator()) {
  19462. case '>':
  19463. $minDepth = $comparator->getTarget() + 1;
  19464. break;
  19465. case '>=':
  19466. $minDepth = $comparator->getTarget();
  19467. break;
  19468. case '<':
  19469. $maxDepth = $comparator->getTarget() - 1;
  19470. break;
  19471. case '<=':
  19472. $maxDepth = $comparator->getTarget();
  19473. break;
  19474. default:
  19475. $minDepth = $maxDepth = $comparator->getTarget();
  19476. }
  19477. }
  19478. $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
  19479. if ($this->followLinks) {
  19480. $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
  19481. }
  19482. $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
  19483. if ($exclude) {
  19484. $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
  19485. }
  19486. $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
  19487. if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) {
  19488. $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
  19489. }
  19490. if ($this->mode) {
  19491. $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
  19492. }
  19493. if ($this->names || $this->notNames) {
  19494. $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
  19495. }
  19496. if ($this->contains || $this->notContains) {
  19497. $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
  19498. }
  19499. if ($this->sizes) {
  19500. $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
  19501. }
  19502. if ($this->dates) {
  19503. $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
  19504. }
  19505. if ($this->filters) {
  19506. $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
  19507. }
  19508. if ($this->paths || $notPaths) {
  19509. $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
  19510. }
  19511. if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) {
  19512. $iterator = new Iterator\VcsIgnoredFilterIterator($iterator, $dir);
  19513. }
  19514. return $iterator;
  19515. }
  19516. private function normalizeDir(string $dir): string
  19517. {
  19518. if ('/' === $dir) {
  19519. return $dir;
  19520. }
  19521. $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
  19522. if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
  19523. $dir .= '/';
  19524. }
  19525. return $dir;
  19526. }
  19527. }
  19528. <?php
  19529. namespace Symfony\Component\Finder;
  19530. class Glob
  19531. {
  19532. public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#')
  19533. {
  19534. $firstByte = true;
  19535. $escaping = false;
  19536. $inCurlies = 0;
  19537. $regex = '';
  19538. $sizeGlob = \strlen($glob);
  19539. for ($i = 0; $i < $sizeGlob; ++$i) {
  19540. $car = $glob[$i];
  19541. if ($firstByte && $strictLeadingDot && '.' !== $car) {
  19542. $regex .= '(?=[^\.])';
  19543. }
  19544. $firstByte = '/' === $car;
  19545. if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {
  19546. $car = '[^/]++/';
  19547. if (!isset($glob[$i + 3])) {
  19548. $car .= '?';
  19549. }
  19550. if ($strictLeadingDot) {
  19551. $car = '(?=[^\.])'.$car;
  19552. }
  19553. $car = '/(?:'.$car.')*';
  19554. $i += 2 + isset($glob[$i + 3]);
  19555. if ('/' === $delimiter) {
  19556. $car = str_replace('/', '\\/', $car);
  19557. }
  19558. }
  19559. if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
  19560. $regex .= "\\$car";
  19561. } elseif ('*' === $car) {
  19562. $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
  19563. } elseif ('?' === $car) {
  19564. $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
  19565. } elseif ('{' === $car) {
  19566. $regex .= $escaping ? '\\{' : '(';
  19567. if (!$escaping) {
  19568. ++$inCurlies;
  19569. }
  19570. } elseif ('}' === $car && $inCurlies) {
  19571. $regex .= $escaping ? '}' : ')';
  19572. if (!$escaping) {
  19573. --$inCurlies;
  19574. }
  19575. } elseif (',' === $car && $inCurlies) {
  19576. $regex .= $escaping ? ',' : '|';
  19577. } elseif ('\\' === $car) {
  19578. if ($escaping) {
  19579. $regex .= '\\\\';
  19580. $escaping = false;
  19581. } else {
  19582. $escaping = true;
  19583. }
  19584. continue;
  19585. } else {
  19586. $regex .= $car;
  19587. }
  19588. $escaping = false;
  19589. }
  19590. return $delimiter.'^'.$regex.'$'.$delimiter;
  19591. }
  19592. }
  19593. <?php
  19594. namespace Symfony\Component\Finder\Iterator;
  19595. class LazyIterator implements \IteratorAggregate
  19596. {
  19597. private $iteratorFactory;
  19598. public function __construct(callable $iteratorFactory)
  19599. {
  19600. $this->iteratorFactory = $iteratorFactory;
  19601. }
  19602. public function getIterator(): \Traversable
  19603. {
  19604. yield from ($this->iteratorFactory)();
  19605. }
  19606. }
  19607. <?php
  19608. namespace Symfony\Component\Finder\Iterator;
  19609. use Symfony\Component\Finder\Gitignore;
  19610. final class VcsIgnoredFilterIterator extends \FilterIterator
  19611. {
  19612. private $baseDir;
  19613. private $gitignoreFilesCache = [];
  19614. private $ignoredPathsCache = [];
  19615. public function __construct(\Iterator $iterator, string $baseDir)
  19616. {
  19617. $this->baseDir = $this->normalizePath($baseDir);
  19618. parent::__construct($iterator);
  19619. }
  19620. public function accept(): bool
  19621. {
  19622. $file = $this->current();
  19623. $fileRealPath = $this->normalizePath($file->getRealPath());
  19624. return !$this->isIgnored($fileRealPath);
  19625. }
  19626. private function isIgnored(string $fileRealPath): bool
  19627. {
  19628. if (is_dir($fileRealPath) && !str_ends_with($fileRealPath, '/')) {
  19629. $fileRealPath .= '/';
  19630. }
  19631. if (isset($this->ignoredPathsCache[$fileRealPath])) {
  19632. return $this->ignoredPathsCache[$fileRealPath];
  19633. }
  19634. $ignored = false;
  19635. foreach ($this->parentsDirectoryDownward($fileRealPath) as $parentDirectory) {
  19636. if ($this->isIgnored($parentDirectory)) {
  19637. break;
  19638. }
  19639. $fileRelativePath = substr($fileRealPath, \strlen($parentDirectory) + 1);
  19640. if (null === $regexps = $this->readGitignoreFile("{$parentDirectory}/.gitignore")) {
  19641. continue;
  19642. }
  19643. [$exclusionRegex, $inclusionRegex] = $regexps;
  19644. if (preg_match($exclusionRegex, $fileRelativePath)) {
  19645. $ignored = true;
  19646. continue;
  19647. }
  19648. if (preg_match($inclusionRegex, $fileRelativePath)) {
  19649. $ignored = false;
  19650. }
  19651. }
  19652. return $this->ignoredPathsCache[$fileRealPath] = $ignored;
  19653. }
  19654. private function parentsDirectoryDownward(string $fileRealPath): array
  19655. {
  19656. $parentDirectories = [];
  19657. $parentDirectory = $fileRealPath;
  19658. while (true) {
  19659. $newParentDirectory = \dirname($parentDirectory);
  19660. if ($newParentDirectory === $parentDirectory) {
  19661. break;
  19662. }
  19663. $parentDirectory = $newParentDirectory;
  19664. if (0 !== strpos($parentDirectory, $this->baseDir)) {
  19665. break;
  19666. }
  19667. $parentDirectories[] = $parentDirectory;
  19668. }
  19669. return array_reverse($parentDirectories);
  19670. }
  19671. private function readGitignoreFile(string $path): ?array
  19672. {
  19673. if (\array_key_exists($path, $this->gitignoreFilesCache)) {
  19674. return $this->gitignoreFilesCache[$path];
  19675. }
  19676. if (!file_exists($path)) {
  19677. return $this->gitignoreFilesCache[$path] = null;
  19678. }
  19679. if (!is_file($path) || !is_readable($path)) {
  19680. throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable.");
  19681. }
  19682. $gitignoreFileContent = file_get_contents($path);
  19683. return $this->gitignoreFilesCache[$path] = [
  19684. Gitignore::toRegex($gitignoreFileContent),
  19685. Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent),
  19686. ];
  19687. }
  19688. private function normalizePath(string $path): string
  19689. {
  19690. if ('\\' === \DIRECTORY_SEPARATOR) {
  19691. return str_replace('\\', '/', $path);
  19692. }
  19693. return $path;
  19694. }
  19695. }
  19696. <?php
  19697. namespace Symfony\Component\Finder\Iterator;
  19698. /**
  19699. @extends
  19700. */
  19701. class FilecontentFilterIterator extends MultiplePcreFilterIterator
  19702. {
  19703. #[\ReturnTypeWillChange]
  19704. public function accept()
  19705. {
  19706. if (!$this->matchRegexps && !$this->noMatchRegexps) {
  19707. return true;
  19708. }
  19709. $fileinfo = $this->current();
  19710. if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
  19711. return false;
  19712. }
  19713. $content = $fileinfo->getContents();
  19714. if (!$content) {
  19715. return false;
  19716. }
  19717. return $this->isAccepted($content);
  19718. }
  19719. protected function toRegex(string $str)
  19720. {
  19721. return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
  19722. }
  19723. }
  19724. <?php
  19725. namespace Symfony\Component\Finder\Iterator;
  19726. /**
  19727. @template-covariant
  19728. @template-covariant
  19729. @extends
  19730. */
  19731. abstract class MultiplePcreFilterIterator extends \FilterIterator
  19732. {
  19733. protected $matchRegexps = [];
  19734. protected $noMatchRegexps = [];
  19735. public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
  19736. {
  19737. foreach ($matchPatterns as $pattern) {
  19738. $this->matchRegexps[] = $this->toRegex($pattern);
  19739. }
  19740. foreach ($noMatchPatterns as $pattern) {
  19741. $this->noMatchRegexps[] = $this->toRegex($pattern);
  19742. }
  19743. parent::__construct($iterator);
  19744. }
  19745. protected function isAccepted(string $string)
  19746. {
  19747. foreach ($this->noMatchRegexps as $regex) {
  19748. if (preg_match($regex, $string)) {
  19749. return false;
  19750. }
  19751. }
  19752. if ($this->matchRegexps) {
  19753. foreach ($this->matchRegexps as $regex) {
  19754. if (preg_match($regex, $string)) {
  19755. return true;
  19756. }
  19757. }
  19758. return false;
  19759. }
  19760. return true;
  19761. }
  19762. protected function isRegex(string $str)
  19763. {
  19764. $availableModifiers = 'imsxuADU';
  19765. if (\PHP_VERSION_ID >= 80200) {
  19766. $availableModifiers .= 'n';
  19767. }
  19768. if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) {
  19769. $start = substr($m[1], 0, 1);
  19770. $end = substr($m[1], -1);
  19771. if ($start === $end) {
  19772. return !preg_match('/[*?[:alnum:] \\\\]/', $start);
  19773. }
  19774. foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
  19775. if ($start === $delimiters[0] && $end === $delimiters[1]) {
  19776. return true;
  19777. }
  19778. }
  19779. }
  19780. return false;
  19781. }
  19782. abstract protected function toRegex(string $str);
  19783. }
  19784. <?php
  19785. namespace Symfony\Component\Finder\Iterator;
  19786. use Symfony\Component\Finder\Comparator\NumberComparator;
  19787. /**
  19788. @extends
  19789. */
  19790. class SizeRangeFilterIterator extends \FilterIterator
  19791. {
  19792. private $comparators = [];
  19793. public function __construct(\Iterator $iterator, array $comparators)
  19794. {
  19795. $this->comparators = $comparators;
  19796. parent::__construct($iterator);
  19797. }
  19798. #[\ReturnTypeWillChange]
  19799. public function accept()
  19800. {
  19801. $fileinfo = $this->current();
  19802. if (!$fileinfo->isFile()) {
  19803. return true;
  19804. }
  19805. $filesize = $fileinfo->getSize();
  19806. foreach ($this->comparators as $compare) {
  19807. if (!$compare->test($filesize)) {
  19808. return false;
  19809. }
  19810. }
  19811. return true;
  19812. }
  19813. }
  19814. <?php
  19815. namespace Symfony\Component\Finder\Iterator;
  19816. use Symfony\Component\Finder\Glob;
  19817. /**
  19818. @extends
  19819. */
  19820. class FilenameFilterIterator extends MultiplePcreFilterIterator
  19821. {
  19822. #[\ReturnTypeWillChange]
  19823. public function accept()
  19824. {
  19825. return $this->isAccepted($this->current()->getFilename());
  19826. }
  19827. protected function toRegex(string $str)
  19828. {
  19829. return $this->isRegex($str) ? $str : Glob::toRegex($str);
  19830. }
  19831. }
  19832. <?php
  19833. namespace Symfony\Component\Finder\Iterator;
  19834. use Symfony\Component\Finder\Comparator\DateComparator;
  19835. /**
  19836. @extends
  19837. */
  19838. class DateRangeFilterIterator extends \FilterIterator
  19839. {
  19840. private $comparators = [];
  19841. public function __construct(\Iterator $iterator, array $comparators)
  19842. {
  19843. $this->comparators = $comparators;
  19844. parent::__construct($iterator);
  19845. }
  19846. #[\ReturnTypeWillChange]
  19847. public function accept()
  19848. {
  19849. $fileinfo = $this->current();
  19850. if (!file_exists($fileinfo->getPathname())) {
  19851. return false;
  19852. }
  19853. $filedate = $fileinfo->getMTime();
  19854. foreach ($this->comparators as $compare) {
  19855. if (!$compare->test($filedate)) {
  19856. return false;
  19857. }
  19858. }
  19859. return true;
  19860. }
  19861. }
  19862. <?php
  19863. namespace Symfony\Component\Finder\Iterator;
  19864. /**
  19865. @extends
  19866. */
  19867. class CustomFilterIterator extends \FilterIterator
  19868. {
  19869. private $filters = [];
  19870. public function __construct(\Iterator $iterator, array $filters)
  19871. {
  19872. foreach ($filters as $filter) {
  19873. if (!\is_callable($filter)) {
  19874. throw new \InvalidArgumentException('Invalid PHP callback.');
  19875. }
  19876. }
  19877. $this->filters = $filters;
  19878. parent::__construct($iterator);
  19879. }
  19880. #[\ReturnTypeWillChange]
  19881. public function accept()
  19882. {
  19883. $fileinfo = $this->current();
  19884. foreach ($this->filters as $filter) {
  19885. if (false === $filter($fileinfo)) {
  19886. return false;
  19887. }
  19888. }
  19889. return true;
  19890. }
  19891. }
  19892. <?php
  19893. namespace Symfony\Component\Finder\Iterator;
  19894. use Symfony\Component\Finder\Exception\AccessDeniedException;
  19895. use Symfony\Component\Finder\SplFileInfo;
  19896. class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
  19897. {
  19898. private $ignoreUnreadableDirs;
  19899. private $ignoreFirstRewind = true;
  19900. private $rootPath;
  19901. private $subPath;
  19902. private $directorySeparator = '/';
  19903. public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
  19904. {
  19905. if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
  19906. throw new \RuntimeException('This iterator only support returning current as fileinfo.');
  19907. }
  19908. parent::__construct($path, $flags);
  19909. $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
  19910. $this->rootPath = $path;
  19911. if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
  19912. $this->directorySeparator = \DIRECTORY_SEPARATOR;
  19913. }
  19914. }
  19915. #[\ReturnTypeWillChange]
  19916. public function current()
  19917. {
  19918. if (null === $subPathname = $this->subPath) {
  19919. $subPathname = $this->subPath = $this->getSubPath();
  19920. }
  19921. if ('' !== $subPathname) {
  19922. $subPathname .= $this->directorySeparator;
  19923. }
  19924. $subPathname .= $this->getFilename();
  19925. $basePath = $this->rootPath;
  19926. if ('/' !== $basePath && !str_ends_with($basePath, $this->directorySeparator) && !str_ends_with($basePath, '/')) {
  19927. $basePath .= $this->directorySeparator;
  19928. }
  19929. return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
  19930. }
  19931. #[\ReturnTypeWillChange]
  19932. public function hasChildren($allowLinks = false)
  19933. {
  19934. $hasChildren = parent::hasChildren($allowLinks);
  19935. if (!$hasChildren || !$this->ignoreUnreadableDirs) {
  19936. return $hasChildren;
  19937. }
  19938. try {
  19939. parent::getChildren();
  19940. return true;
  19941. } catch (\UnexpectedValueException $e) {
  19942. return false;
  19943. }
  19944. }
  19945. #[\ReturnTypeWillChange]
  19946. public function getChildren()
  19947. {
  19948. try {
  19949. $children = parent::getChildren();
  19950. if ($children instanceof self) {
  19951. $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
  19952. $children->rootPath = $this->rootPath;
  19953. }
  19954. return $children;
  19955. } catch (\UnexpectedValueException $e) {
  19956. throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
  19957. }
  19958. }
  19959. #[\ReturnTypeWillChange]
  19960. public function next()
  19961. {
  19962. $this->ignoreFirstRewind = false;
  19963. parent::next();
  19964. }
  19965. #[\ReturnTypeWillChange]
  19966. public function rewind()
  19967. {
  19968. if ($this->ignoreFirstRewind) {
  19969. $this->ignoreFirstRewind = false;
  19970. return;
  19971. }
  19972. parent::rewind();
  19973. }
  19974. }
  19975. <?php
  19976. namespace Symfony\Component\Finder\Iterator;
  19977. /**
  19978. @extends
  19979. @implements
  19980. */
  19981. class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
  19982. {
  19983. private $iterator;
  19984. private $isRecursive;
  19985. private $excludedDirs = [];
  19986. private $excludedPattern;
  19987. public function __construct(\Iterator $iterator, array $directories)
  19988. {
  19989. $this->iterator = $iterator;
  19990. $this->isRecursive = $iterator instanceof \RecursiveIterator;
  19991. $patterns = [];
  19992. foreach ($directories as $directory) {
  19993. $directory = rtrim($directory, '/');
  19994. if (!$this->isRecursive || str_contains($directory, '/')) {
  19995. $patterns[] = preg_quote($directory, '#');
  19996. } else {
  19997. $this->excludedDirs[$directory] = true;
  19998. }
  19999. }
  20000. if ($patterns) {
  20001. $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
  20002. }
  20003. parent::__construct($iterator);
  20004. }
  20005. #[\ReturnTypeWillChange]
  20006. public function accept()
  20007. {
  20008. if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
  20009. return false;
  20010. }
  20011. if ($this->excludedPattern) {
  20012. $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
  20013. $path = str_replace('\\', '/', $path);
  20014. return !preg_match($this->excludedPattern, $path);
  20015. }
  20016. return true;
  20017. }
  20018. #[\ReturnTypeWillChange]
  20019. public function hasChildren()
  20020. {
  20021. return $this->isRecursive && $this->iterator->hasChildren();
  20022. }
  20023. #[\ReturnTypeWillChange]
  20024. public function getChildren()
  20025. {
  20026. $children = new self($this->iterator->getChildren(), []);
  20027. $children->excludedDirs = $this->excludedDirs;
  20028. $children->excludedPattern = $this->excludedPattern;
  20029. return $children;
  20030. }
  20031. }
  20032. <?php
  20033. namespace Symfony\Component\Finder\Iterator;
  20034. /**
  20035. @implements
  20036. */
  20037. class SortableIterator implements \IteratorAggregate
  20038. {
  20039. public const SORT_BY_NONE = 0;
  20040. public const SORT_BY_NAME = 1;
  20041. public const SORT_BY_TYPE = 2;
  20042. public const SORT_BY_ACCESSED_TIME = 3;
  20043. public const SORT_BY_CHANGED_TIME = 4;
  20044. public const SORT_BY_MODIFIED_TIME = 5;
  20045. public const SORT_BY_NAME_NATURAL = 6;
  20046. private $iterator;
  20047. private $sort;
  20048. public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
  20049. {
  20050. $this->iterator = $iterator;
  20051. $order = $reverseOrder ? -1 : 1;
  20052. if (self::SORT_BY_NAME === $sort) {
  20053. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20054. return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
  20055. };
  20056. } elseif (self::SORT_BY_NAME_NATURAL === $sort) {
  20057. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20058. return $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
  20059. };
  20060. } elseif (self::SORT_BY_TYPE === $sort) {
  20061. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20062. if ($a->isDir() && $b->isFile()) {
  20063. return -$order;
  20064. } elseif ($a->isFile() && $b->isDir()) {
  20065. return $order;
  20066. }
  20067. return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
  20068. };
  20069. } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
  20070. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20071. return $order * ($a->getATime() - $b->getATime());
  20072. };
  20073. } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
  20074. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20075. return $order * ($a->getCTime() - $b->getCTime());
  20076. };
  20077. } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
  20078. $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
  20079. return $order * ($a->getMTime() - $b->getMTime());
  20080. };
  20081. } elseif (self::SORT_BY_NONE === $sort) {
  20082. $this->sort = $order;
  20083. } elseif (\is_callable($sort)) {
  20084. $this->sort = $reverseOrder ? static function (\SplFileInfo $a, \SplFileInfo $b) use ($sort) { return -$sort($a, $b); } : $sort;
  20085. } else {
  20086. throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
  20087. }
  20088. }
  20089. #[\ReturnTypeWillChange]
  20090. public function getIterator()
  20091. {
  20092. if (1 === $this->sort) {
  20093. return $this->iterator;
  20094. }
  20095. $array = iterator_to_array($this->iterator, true);
  20096. if (-1 === $this->sort) {
  20097. $array = array_reverse($array);
  20098. } else {
  20099. uasort($array, $this->sort);
  20100. }
  20101. return new \ArrayIterator($array);
  20102. }
  20103. }
  20104. <?php
  20105. namespace Symfony\Component\Finder\Iterator;
  20106. /**
  20107. @template-covariant
  20108. @template-covariant
  20109. @extends
  20110. */
  20111. class DepthRangeFilterIterator extends \FilterIterator
  20112. {
  20113. private $minDepth = 0;
  20114. public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \PHP_INT_MAX)
  20115. {
  20116. $this->minDepth = $minDepth;
  20117. $iterator->setMaxDepth(\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
  20118. parent::__construct($iterator);
  20119. }
  20120. #[\ReturnTypeWillChange]
  20121. public function accept()
  20122. {
  20123. return $this->getInnerIterator()->getDepth() >= $this->minDepth;
  20124. }
  20125. }
  20126. <?php
  20127. namespace Symfony\Component\Finder\Iterator;
  20128. /**
  20129. @extends
  20130. */
  20131. class FileTypeFilterIterator extends \FilterIterator
  20132. {
  20133. public const ONLY_FILES = 1;
  20134. public const ONLY_DIRECTORIES = 2;
  20135. private $mode;
  20136. public function __construct(\Iterator $iterator, int $mode)
  20137. {
  20138. $this->mode = $mode;
  20139. parent::__construct($iterator);
  20140. }
  20141. #[\ReturnTypeWillChange]
  20142. public function accept()
  20143. {
  20144. $fileinfo = $this->current();
  20145. if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
  20146. return false;
  20147. } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
  20148. return false;
  20149. }
  20150. return true;
  20151. }
  20152. }
  20153. <?php
  20154. namespace Symfony\Component\Finder\Iterator;
  20155. /**
  20156. @extends
  20157. */
  20158. class PathFilterIterator extends MultiplePcreFilterIterator
  20159. {
  20160. #[\ReturnTypeWillChange]
  20161. public function accept()
  20162. {
  20163. $filename = $this->current()->getRelativePathname();
  20164. if ('\\' === \DIRECTORY_SEPARATOR) {
  20165. $filename = str_replace('\\', '/', $filename);
  20166. }
  20167. return $this->isAccepted($filename);
  20168. }
  20169. protected function toRegex(string $str)
  20170. {
  20171. return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
  20172. }
  20173. }
  20174. <?php
  20175. namespace Symfony\Component\Finder;
  20176. class Gitignore
  20177. {
  20178. public static function toRegex(string $gitignoreFileContent): string
  20179. {
  20180. return self::buildRegex($gitignoreFileContent, false);
  20181. }
  20182. public static function toRegexMatchingNegatedPatterns(string $gitignoreFileContent): string
  20183. {
  20184. return self::buildRegex($gitignoreFileContent, true);
  20185. }
  20186. private static function buildRegex(string $gitignoreFileContent, bool $inverted): string
  20187. {
  20188. $gitignoreFileContent = preg_replace('~(?<!\\\\)#[^\n\r]*~', '', $gitignoreFileContent);
  20189. $gitignoreLines = preg_split('~\r\n?|\n~', $gitignoreFileContent);
  20190. $res = self::lineToRegex('');
  20191. foreach ($gitignoreLines as $line) {
  20192. $line = preg_replace('~(?<!\\\\)[ \t]+$~', '', $line);
  20193. if ('!' === substr($line, 0, 1)) {
  20194. $line = substr($line, 1);
  20195. $isNegative = true;
  20196. } else {
  20197. $isNegative = false;
  20198. }
  20199. if ('' !== $line) {
  20200. if ($isNegative xor $inverted) {
  20201. $res = '(?!'.self::lineToRegex($line).'$)'.$res;
  20202. } else {
  20203. $res = '(?:'.$res.'|'.self::lineToRegex($line).')';
  20204. }
  20205. }
  20206. }
  20207. return '~^(?:'.$res.')~s';
  20208. }
  20209. private static function lineToRegex(string $gitignoreLine): string
  20210. {
  20211. if ('' === $gitignoreLine) {
  20212. return '$f';
  20213. }
  20214. $slashPos = strpos($gitignoreLine, '/');
  20215. if (false !== $slashPos && \strlen($gitignoreLine) - 1 !== $slashPos) {
  20216. if (0 === $slashPos) {
  20217. $gitignoreLine = substr($gitignoreLine, 1);
  20218. }
  20219. $isAbsolute = true;
  20220. } else {
  20221. $isAbsolute = false;
  20222. }
  20223. $regex = preg_quote(str_replace('\\', '', $gitignoreLine), '~');
  20224. $regex = preg_replace_callback('~\\\\\[((?:\\\\!)?)([^\[\]]*)\\\\\]~', function (array $matches): string {
  20225. return '['.('' !== $matches[1] ? '^' : '').str_replace('\\-', '-', $matches[2]).']';
  20226. }, $regex);
  20227. $regex = preg_replace('~(?:(?:\\\\\*){2,}(/?))+~', '(?:(?:(?!//).(?<!//))+$1)?', $regex);
  20228. $regex = preg_replace('~\\\\\*~', '[^/]*', $regex);
  20229. $regex = preg_replace('~\\\\\?~', '[^/]', $regex);
  20230. return ($isAbsolute ? '' : '(?:[^/]+/)*')
  20231. .$regex
  20232. .(!str_ends_with($gitignoreLine, '/') ? '(?:$|/)' : '');
  20233. }
  20234. }
  20235. <?php
  20236. namespace Symfony\Component\Finder\Exception;
  20237. class AccessDeniedException extends \UnexpectedValueException
  20238. {
  20239. }
  20240. <?php
  20241. namespace Symfony\Component\Finder\Exception;
  20242. class DirectoryNotFoundException extends \InvalidArgumentException
  20243. {
  20244. }
  20245. <?php
  20246. namespace Symfony\Component\Stopwatch;
  20247. use Symfony\Contracts\Service\ResetInterface;
  20248. class_exists(Section::class);
  20249. class Stopwatch implements ResetInterface
  20250. {
  20251. private $morePrecision;
  20252. private $sections;
  20253. private $activeSections;
  20254. public function __construct(bool $morePrecision = false)
  20255. {
  20256. $this->morePrecision = $morePrecision;
  20257. $this->reset();
  20258. }
  20259. public function getSections()
  20260. {
  20261. return $this->sections;
  20262. }
  20263. public function openSection(?string $id = null)
  20264. {
  20265. $current = end($this->activeSections);
  20266. if (null !== $id && null === $current->get($id)) {
  20267. throw new \LogicException(sprintf('The section "%s" has been started at an other level and cannot be opened.', $id));
  20268. }
  20269. $this->start('__section__.child', 'section');
  20270. $this->activeSections[] = $current->open($id);
  20271. $this->start('__section__');
  20272. }
  20273. public function stopSection(string $id)
  20274. {
  20275. $this->stop('__section__');
  20276. if (1 == \count($this->activeSections)) {
  20277. throw new \LogicException('There is no started section to stop.');
  20278. }
  20279. $this->sections[$id] = array_pop($this->activeSections)->setId($id);
  20280. $this->stop('__section__.child');
  20281. }
  20282. public function start(string $name, ?string $category = null)
  20283. {
  20284. return end($this->activeSections)->startEvent($name, $category);
  20285. }
  20286. public function isStarted(string $name)
  20287. {
  20288. return end($this->activeSections)->isEventStarted($name);
  20289. }
  20290. public function stop(string $name)
  20291. {
  20292. return end($this->activeSections)->stopEvent($name);
  20293. }
  20294. public function lap(string $name)
  20295. {
  20296. return end($this->activeSections)->stopEvent($name)->start();
  20297. }
  20298. public function getEvent(string $name)
  20299. {
  20300. return end($this->activeSections)->getEvent($name);
  20301. }
  20302. public function getSectionEvents(string $id)
  20303. {
  20304. return isset($this->sections[$id]) ? $this->sections[$id]->getEvents() : [];
  20305. }
  20306. public function reset()
  20307. {
  20308. $this->sections = $this->activeSections = ['__root__' => new Section(null, $this->morePrecision)];
  20309. }
  20310. }
  20311. <?php
  20312. namespace Symfony\Component\Stopwatch;
  20313. class Section
  20314. {
  20315. private $events = [];
  20316. private $origin;
  20317. private $morePrecision;
  20318. private $id;
  20319. private $children = [];
  20320. public function __construct(?float $origin = null, bool $morePrecision = false)
  20321. {
  20322. $this->origin = $origin;
  20323. $this->morePrecision = $morePrecision;
  20324. }
  20325. public function get(string $id)
  20326. {
  20327. foreach ($this->children as $child) {
  20328. if ($id === $child->getId()) {
  20329. return $child;
  20330. }
  20331. }
  20332. return null;
  20333. }
  20334. public function open(?string $id)
  20335. {
  20336. if (null === $id || null === $session = $this->get($id)) {
  20337. $session = $this->children[] = new self(microtime(true) * 1000, $this->morePrecision);
  20338. }
  20339. return $session;
  20340. }
  20341. public function getId()
  20342. {
  20343. return $this->id;
  20344. }
  20345. public function setId(string $id)
  20346. {
  20347. $this->id = $id;
  20348. return $this;
  20349. }
  20350. public function startEvent(string $name, ?string $category)
  20351. {
  20352. if (!isset($this->events[$name])) {
  20353. $this->events[$name] = new StopwatchEvent($this->origin ?: microtime(true) * 1000, $category, $this->morePrecision, $name);
  20354. }
  20355. return $this->events[$name]->start();
  20356. }
  20357. public function isEventStarted(string $name)
  20358. {
  20359. return isset($this->events[$name]) && $this->events[$name]->isStarted();
  20360. }
  20361. public function stopEvent(string $name)
  20362. {
  20363. if (!isset($this->events[$name])) {
  20364. throw new \LogicException(sprintf('Event "%s" is not started.', $name));
  20365. }
  20366. return $this->events[$name]->stop();
  20367. }
  20368. public function lap(string $name)
  20369. {
  20370. return $this->stopEvent($name)->start();
  20371. }
  20372. public function getEvent(string $name)
  20373. {
  20374. if (!isset($this->events[$name])) {
  20375. throw new \LogicException(sprintf('Event "%s" is not known.', $name));
  20376. }
  20377. return $this->events[$name];
  20378. }
  20379. public function getEvents()
  20380. {
  20381. return $this->events;
  20382. }
  20383. }
  20384. <?php
  20385. namespace Symfony\Component\Stopwatch;
  20386. class StopwatchPeriod
  20387. {
  20388. private $start;
  20389. private $end;
  20390. private $memory;
  20391. public function __construct($start, $end, bool $morePrecision = false)
  20392. {
  20393. $this->start = $morePrecision ? (float) $start : (int) $start;
  20394. $this->end = $morePrecision ? (float) $end : (int) $end;
  20395. $this->memory = memory_get_usage(true);
  20396. }
  20397. public function getStartTime()
  20398. {
  20399. return $this->start;
  20400. }
  20401. public function getEndTime()
  20402. {
  20403. return $this->end;
  20404. }
  20405. public function getDuration()
  20406. {
  20407. return $this->end - $this->start;
  20408. }
  20409. public function getMemory()
  20410. {
  20411. return $this->memory;
  20412. }
  20413. public function __toString(): string
  20414. {
  20415. return sprintf('%.2F MiB - %d ms', $this->getMemory() / 1024 / 1024, $this->getDuration());
  20416. }
  20417. }
  20418. <?php
  20419. namespace Symfony\Component\Stopwatch;
  20420. class StopwatchEvent
  20421. {
  20422. private $periods = [];
  20423. private $origin;
  20424. private $category;
  20425. private $morePrecision;
  20426. private $started = [];
  20427. private $name;
  20428. public function __construct(float $origin, ?string $category = null, bool $morePrecision = false, ?string $name = null)
  20429. {
  20430. $this->origin = $this->formatTime($origin);
  20431. $this->category = \is_string($category) ? $category : 'default';
  20432. $this->morePrecision = $morePrecision;
  20433. $this->name = $name ?? 'default';
  20434. }
  20435. public function getCategory()
  20436. {
  20437. return $this->category;
  20438. }
  20439. public function getOrigin()
  20440. {
  20441. return $this->origin;
  20442. }
  20443. public function start()
  20444. {
  20445. $this->started[] = $this->getNow();
  20446. return $this;
  20447. }
  20448. public function stop()
  20449. {
  20450. if (!\count($this->started)) {
  20451. throw new \LogicException('stop() called but start() has not been called before.');
  20452. }
  20453. $this->periods[] = new StopwatchPeriod(array_pop($this->started), $this->getNow(), $this->morePrecision);
  20454. return $this;
  20455. }
  20456. public function isStarted()
  20457. {
  20458. return !empty($this->started);
  20459. }
  20460. public function lap()
  20461. {
  20462. return $this->stop()->start();
  20463. }
  20464. public function ensureStopped()
  20465. {
  20466. while (\count($this->started)) {
  20467. $this->stop();
  20468. }
  20469. }
  20470. public function getPeriods()
  20471. {
  20472. return $this->periods;
  20473. }
  20474. public function getStartTime()
  20475. {
  20476. if (isset($this->periods[0])) {
  20477. return $this->periods[0]->getStartTime();
  20478. }
  20479. if ($this->started) {
  20480. return $this->started[0];
  20481. }
  20482. return 0;
  20483. }
  20484. public function getEndTime()
  20485. {
  20486. $count = \count($this->periods);
  20487. return $count ? $this->periods[$count - 1]->getEndTime() : 0;
  20488. }
  20489. public function getDuration()
  20490. {
  20491. $periods = $this->periods;
  20492. $left = \count($this->started);
  20493. for ($i = $left - 1; $i >= 0; --$i) {
  20494. $periods[] = new StopwatchPeriod($this->started[$i], $this->getNow(), $this->morePrecision);
  20495. }
  20496. $total = 0;
  20497. foreach ($periods as $period) {
  20498. $total += $period->getDuration();
  20499. }
  20500. return $total;
  20501. }
  20502. public function getMemory()
  20503. {
  20504. $memory = 0;
  20505. foreach ($this->periods as $period) {
  20506. if ($period->getMemory() > $memory) {
  20507. $memory = $period->getMemory();
  20508. }
  20509. }
  20510. return $memory;
  20511. }
  20512. protected function getNow()
  20513. {
  20514. return $this->formatTime(microtime(true) * 1000 - $this->origin);
  20515. }
  20516. private function formatTime(float $time): float
  20517. {
  20518. return round($time, 1);
  20519. }
  20520. public function getName(): string
  20521. {
  20522. return $this->name;
  20523. }
  20524. public function __toString(): string
  20525. {
  20526. return sprintf('%s/%s: %.2F MiB - %d ms', $this->getCategory(), $this->getName(), $this->getMemory() / 1024 / 1024, $this->getDuration());
  20527. }
  20528. }
  20529. <?php
  20530. namespace Symfony\Component\String;
  20531. use Symfony\Component\String\Exception\ExceptionInterface;
  20532. use Symfony\Component\String\Exception\InvalidArgumentException;
  20533. class CodePointString extends AbstractUnicodeString
  20534. {
  20535. public function __construct(string $string = '')
  20536. {
  20537. if ('' !== $string && !preg_match('//u', $string)) {
  20538. throw new InvalidArgumentException('Invalid UTF-8 string.');
  20539. }
  20540. $this->string = $string;
  20541. }
  20542. public function append(string ...$suffix): AbstractString
  20543. {
  20544. $str = clone $this;
  20545. $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);
  20546. if (!preg_match('//u', $str->string)) {
  20547. throw new InvalidArgumentException('Invalid UTF-8 string.');
  20548. }
  20549. return $str;
  20550. }
  20551. public function chunk(int $length = 1): array
  20552. {
  20553. if (1 > $length) {
  20554. throw new InvalidArgumentException('The chunk length must be greater than zero.');
  20555. }
  20556. if ('' === $this->string) {
  20557. return [];
  20558. }
  20559. $rx = '/(';
  20560. while (65535 < $length) {
  20561. $rx .= '.{65535}';
  20562. $length -= 65535;
  20563. }
  20564. $rx .= '.{'.$length.'})/us';
  20565. $str = clone $this;
  20566. $chunks = [];
  20567. foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
  20568. $str->string = $chunk;
  20569. $chunks[] = clone $str;
  20570. }
  20571. return $chunks;
  20572. }
  20573. public function codePointsAt(int $offset): array
  20574. {
  20575. $str = $offset ? $this->slice($offset, 1) : $this;
  20576. return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')];
  20577. }
  20578. public function endsWith($suffix): bool
  20579. {
  20580. if ($suffix instanceof AbstractString) {
  20581. $suffix = $suffix->string;
  20582. } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
  20583. return parent::endsWith($suffix);
  20584. } else {
  20585. $suffix = (string) $suffix;
  20586. }
  20587. if ('' === $suffix || !preg_match('//u', $suffix)) {
  20588. return false;
  20589. }
  20590. if ($this->ignoreCase) {
  20591. return preg_match('{'.preg_quote($suffix).'$}iuD', $this->string);
  20592. }
  20593. return \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix));
  20594. }
  20595. public function equalsTo($string): bool
  20596. {
  20597. if ($string instanceof AbstractString) {
  20598. $string = $string->string;
  20599. } elseif (\is_array($string) || $string instanceof \Traversable) {
  20600. return parent::equalsTo($string);
  20601. } else {
  20602. $string = (string) $string;
  20603. }
  20604. if ('' !== $string && $this->ignoreCase) {
  20605. return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');
  20606. }
  20607. return $string === $this->string;
  20608. }
  20609. public function indexOf($needle, int $offset = 0): ?int
  20610. {
  20611. if ($needle instanceof AbstractString) {
  20612. $needle = $needle->string;
  20613. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  20614. return parent::indexOf($needle, $offset);
  20615. } else {
  20616. $needle = (string) $needle;
  20617. }
  20618. if ('' === $needle) {
  20619. return null;
  20620. }
  20621. $i = $this->ignoreCase ? mb_stripos($this->string, $needle, $offset, 'UTF-8') : mb_strpos($this->string, $needle, $offset, 'UTF-8');
  20622. return false === $i ? null : $i;
  20623. }
  20624. public function indexOfLast($needle, int $offset = 0): ?int
  20625. {
  20626. if ($needle instanceof AbstractString) {
  20627. $needle = $needle->string;
  20628. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  20629. return parent::indexOfLast($needle, $offset);
  20630. } else {
  20631. $needle = (string) $needle;
  20632. }
  20633. if ('' === $needle) {
  20634. return null;
  20635. }
  20636. $i = $this->ignoreCase ? mb_strripos($this->string, $needle, $offset, 'UTF-8') : mb_strrpos($this->string, $needle, $offset, 'UTF-8');
  20637. return false === $i ? null : $i;
  20638. }
  20639. public function length(): int
  20640. {
  20641. return mb_strlen($this->string, 'UTF-8');
  20642. }
  20643. public function prepend(string ...$prefix): AbstractString
  20644. {
  20645. $str = clone $this;
  20646. $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;
  20647. if (!preg_match('//u', $str->string)) {
  20648. throw new InvalidArgumentException('Invalid UTF-8 string.');
  20649. }
  20650. return $str;
  20651. }
  20652. public function replace(string $from, string $to): AbstractString
  20653. {
  20654. $str = clone $this;
  20655. if ('' === $from || !preg_match('//u', $from)) {
  20656. return $str;
  20657. }
  20658. if ('' !== $to && !preg_match('//u', $to)) {
  20659. throw new InvalidArgumentException('Invalid UTF-8 string.');
  20660. }
  20661. if ($this->ignoreCase) {
  20662. $str->string = implode($to, preg_split('{'.preg_quote($from).'}iuD', $this->string));
  20663. } else {
  20664. $str->string = str_replace($from, $to, $this->string);
  20665. }
  20666. return $str;
  20667. }
  20668. public function slice(int $start = 0, ?int $length = null): AbstractString
  20669. {
  20670. $str = clone $this;
  20671. $str->string = mb_substr($this->string, $start, $length, 'UTF-8');
  20672. return $str;
  20673. }
  20674. public function splice(string $replacement, int $start = 0, ?int $length = null): AbstractString
  20675. {
  20676. if (!preg_match('//u', $replacement)) {
  20677. throw new InvalidArgumentException('Invalid UTF-8 string.');
  20678. }
  20679. $str = clone $this;
  20680. $start = $start ? \strlen(mb_substr($this->string, 0, $start, 'UTF-8')) : 0;
  20681. $length = $length ? \strlen(mb_substr($this->string, $start, $length, 'UTF-8')) : $length;
  20682. $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
  20683. return $str;
  20684. }
  20685. public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
  20686. {
  20687. if (1 > $limit = $limit ?? \PHP_INT_MAX) {
  20688. throw new InvalidArgumentException('Split limit must be a positive integer.');
  20689. }
  20690. if ('' === $delimiter) {
  20691. throw new InvalidArgumentException('Split delimiter is empty.');
  20692. }
  20693. if (null !== $flags) {
  20694. return parent::split($delimiter.'u', $limit, $flags);
  20695. }
  20696. if (!preg_match('//u', $delimiter)) {
  20697. throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
  20698. }
  20699. $str = clone $this;
  20700. $chunks = $this->ignoreCase
  20701. ? preg_split('{'.preg_quote($delimiter).'}iuD', $this->string, $limit)
  20702. : explode($delimiter, $this->string, $limit);
  20703. foreach ($chunks as &$chunk) {
  20704. $str->string = $chunk;
  20705. $chunk = clone $str;
  20706. }
  20707. return $chunks;
  20708. }
  20709. public function startsWith($prefix): bool
  20710. {
  20711. if ($prefix instanceof AbstractString) {
  20712. $prefix = $prefix->string;
  20713. } elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
  20714. return parent::startsWith($prefix);
  20715. } else {
  20716. $prefix = (string) $prefix;
  20717. }
  20718. if ('' === $prefix || !preg_match('//u', $prefix)) {
  20719. return false;
  20720. }
  20721. if ($this->ignoreCase) {
  20722. return 0 === mb_stripos($this->string, $prefix, 0, 'UTF-8');
  20723. }
  20724. return 0 === strncmp($this->string, $prefix, \strlen($prefix));
  20725. }
  20726. }
  20727. <?php
  20728. namespace Symfony\Component\String;
  20729. use Symfony\Component\String\Exception\ExceptionInterface;
  20730. use Symfony\Component\String\Exception\InvalidArgumentException;
  20731. use Symfony\Component\String\Exception\RuntimeException;
  20732. abstract class AbstractString implements \Stringable, \JsonSerializable
  20733. {
  20734. public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER;
  20735. public const PREG_SET_ORDER = \PREG_SET_ORDER;
  20736. public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE;
  20737. public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL;
  20738. public const PREG_SPLIT = 0;
  20739. public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY;
  20740. public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE;
  20741. public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE;
  20742. protected $string = '';
  20743. protected $ignoreCase = false;
  20744. abstract public function __construct(string $string = '');
  20745. public static function unwrap(array $values): array
  20746. {
  20747. foreach ($values as $k => $v) {
  20748. if ($v instanceof self) {
  20749. $values[$k] = $v->__toString();
  20750. } elseif (\is_array($v) && $values[$k] !== $v = static::unwrap($v)) {
  20751. $values[$k] = $v;
  20752. }
  20753. }
  20754. return $values;
  20755. }
  20756. public static function wrap(array $values): array
  20757. {
  20758. $i = 0;
  20759. $keys = null;
  20760. foreach ($values as $k => $v) {
  20761. if (\is_string($k) && '' !== $k && $k !== $j = (string) new static($k)) {
  20762. $keys = $keys ?? array_keys($values);
  20763. $keys[$i] = $j;
  20764. }
  20765. if (\is_string($v)) {
  20766. $values[$k] = new static($v);
  20767. } elseif (\is_array($v) && $values[$k] !== $v = static::wrap($v)) {
  20768. $values[$k] = $v;
  20769. }
  20770. ++$i;
  20771. }
  20772. return null !== $keys ? array_combine($keys, $values) : $values;
  20773. }
  20774. public function after($needle, bool $includeNeedle = false, int $offset = 0): self
  20775. {
  20776. $str = clone $this;
  20777. $i = \PHP_INT_MAX;
  20778. foreach ((array) $needle as $n) {
  20779. $n = (string) $n;
  20780. $j = $this->indexOf($n, $offset);
  20781. if (null !== $j && $j < $i) {
  20782. $i = $j;
  20783. $str->string = $n;
  20784. }
  20785. }
  20786. if (\PHP_INT_MAX === $i) {
  20787. return $str;
  20788. }
  20789. if (!$includeNeedle) {
  20790. $i += $str->length();
  20791. }
  20792. return $this->slice($i);
  20793. }
  20794. public function afterLast($needle, bool $includeNeedle = false, int $offset = 0): self
  20795. {
  20796. $str = clone $this;
  20797. $i = null;
  20798. foreach ((array) $needle as $n) {
  20799. $n = (string) $n;
  20800. $j = $this->indexOfLast($n, $offset);
  20801. if (null !== $j && $j >= $i) {
  20802. $i = $offset = $j;
  20803. $str->string = $n;
  20804. }
  20805. }
  20806. if (null === $i) {
  20807. return $str;
  20808. }
  20809. if (!$includeNeedle) {
  20810. $i += $str->length();
  20811. }
  20812. return $this->slice($i);
  20813. }
  20814. abstract public function append(string ...$suffix): self;
  20815. public function before($needle, bool $includeNeedle = false, int $offset = 0): self
  20816. {
  20817. $str = clone $this;
  20818. $i = \PHP_INT_MAX;
  20819. foreach ((array) $needle as $n) {
  20820. $n = (string) $n;
  20821. $j = $this->indexOf($n, $offset);
  20822. if (null !== $j && $j < $i) {
  20823. $i = $j;
  20824. $str->string = $n;
  20825. }
  20826. }
  20827. if (\PHP_INT_MAX === $i) {
  20828. return $str;
  20829. }
  20830. if ($includeNeedle) {
  20831. $i += $str->length();
  20832. }
  20833. return $this->slice(0, $i);
  20834. }
  20835. public function beforeLast($needle, bool $includeNeedle = false, int $offset = 0): self
  20836. {
  20837. $str = clone $this;
  20838. $i = null;
  20839. foreach ((array) $needle as $n) {
  20840. $n = (string) $n;
  20841. $j = $this->indexOfLast($n, $offset);
  20842. if (null !== $j && $j >= $i) {
  20843. $i = $offset = $j;
  20844. $str->string = $n;
  20845. }
  20846. }
  20847. if (null === $i) {
  20848. return $str;
  20849. }
  20850. if ($includeNeedle) {
  20851. $i += $str->length();
  20852. }
  20853. return $this->slice(0, $i);
  20854. }
  20855. public function bytesAt(int $offset): array
  20856. {
  20857. $str = $this->slice($offset, 1);
  20858. return '' === $str->string ? [] : array_values(unpack('C*', $str->string));
  20859. }
  20860. abstract public function camel(): self;
  20861. abstract public function chunk(int $length = 1): array;
  20862. public function collapseWhitespace(): self
  20863. {
  20864. $str = clone $this;
  20865. $str->string = trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $str->string), " \n\r\t\x0C");
  20866. return $str;
  20867. }
  20868. public function containsAny($needle): bool
  20869. {
  20870. return null !== $this->indexOf($needle);
  20871. }
  20872. public function endsWith($suffix): bool
  20873. {
  20874. if (!\is_array($suffix) && !$suffix instanceof \Traversable) {
  20875. throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
  20876. }
  20877. foreach ($suffix as $s) {
  20878. if ($this->endsWith((string) $s)) {
  20879. return true;
  20880. }
  20881. }
  20882. return false;
  20883. }
  20884. public function ensureEnd(string $suffix): self
  20885. {
  20886. if (!$this->endsWith($suffix)) {
  20887. return $this->append($suffix);
  20888. }
  20889. $suffix = preg_quote($suffix);
  20890. $regex = '{('.$suffix.')(?:'.$suffix.')++$}D';
  20891. return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1');
  20892. }
  20893. public function ensureStart(string $prefix): self
  20894. {
  20895. $prefix = new static($prefix);
  20896. if (!$this->startsWith($prefix)) {
  20897. return $this->prepend($prefix);
  20898. }
  20899. $str = clone $this;
  20900. $i = $prefixLen = $prefix->length();
  20901. while ($this->indexOf($prefix, $i) === $i) {
  20902. $str = $str->slice($prefixLen);
  20903. $i += $prefixLen;
  20904. }
  20905. return $str;
  20906. }
  20907. public function equalsTo($string): bool
  20908. {
  20909. if (!\is_array($string) && !$string instanceof \Traversable) {
  20910. throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
  20911. }
  20912. foreach ($string as $s) {
  20913. if ($this->equalsTo((string) $s)) {
  20914. return true;
  20915. }
  20916. }
  20917. return false;
  20918. }
  20919. abstract public function folded(): self;
  20920. public function ignoreCase(): self
  20921. {
  20922. $str = clone $this;
  20923. $str->ignoreCase = true;
  20924. return $str;
  20925. }
  20926. public function indexOf($needle, int $offset = 0): ?int
  20927. {
  20928. if (!\is_array($needle) && !$needle instanceof \Traversable) {
  20929. throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
  20930. }
  20931. $i = \PHP_INT_MAX;
  20932. foreach ($needle as $n) {
  20933. $j = $this->indexOf((string) $n, $offset);
  20934. if (null !== $j && $j < $i) {
  20935. $i = $j;
  20936. }
  20937. }
  20938. return \PHP_INT_MAX === $i ? null : $i;
  20939. }
  20940. public function indexOfLast($needle, int $offset = 0): ?int
  20941. {
  20942. if (!\is_array($needle) && !$needle instanceof \Traversable) {
  20943. throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
  20944. }
  20945. $i = null;
  20946. foreach ($needle as $n) {
  20947. $j = $this->indexOfLast((string) $n, $offset);
  20948. if (null !== $j && $j >= $i) {
  20949. $i = $offset = $j;
  20950. }
  20951. }
  20952. return $i;
  20953. }
  20954. public function isEmpty(): bool
  20955. {
  20956. return '' === $this->string;
  20957. }
  20958. abstract public function join(array $strings, ?string $lastGlue = null): self;
  20959. public function jsonSerialize(): string
  20960. {
  20961. return $this->string;
  20962. }
  20963. abstract public function length(): int;
  20964. abstract public function lower(): self;
  20965. abstract public function match(string $regexp, int $flags = 0, int $offset = 0): array;
  20966. abstract public function padBoth(int $length, string $padStr = ' '): self;
  20967. abstract public function padEnd(int $length, string $padStr = ' '): self;
  20968. abstract public function padStart(int $length, string $padStr = ' '): self;
  20969. abstract public function prepend(string ...$prefix): self;
  20970. public function repeat(int $multiplier): self
  20971. {
  20972. if (0 > $multiplier) {
  20973. throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier));
  20974. }
  20975. $str = clone $this;
  20976. $str->string = str_repeat($str->string, $multiplier);
  20977. return $str;
  20978. }
  20979. abstract public function replace(string $from, string $to): self;
  20980. abstract public function replaceMatches(string $fromRegexp, $to): self;
  20981. abstract public function reverse(): self;
  20982. abstract public function slice(int $start = 0, ?int $length = null): self;
  20983. abstract public function snake(): self;
  20984. abstract public function splice(string $replacement, int $start = 0, ?int $length = null): self;
  20985. public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
  20986. {
  20987. if (null === $flags) {
  20988. throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.');
  20989. }
  20990. if ($this->ignoreCase) {
  20991. $delimiter .= 'i';
  20992. }
  20993. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  20994. try {
  20995. if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) {
  20996. $lastError = preg_last_error();
  20997. foreach (get_defined_constants(true)['pcre'] as $k => $v) {
  20998. if ($lastError === $v && '_ERROR' === substr($k, -6)) {
  20999. throw new RuntimeException('Splitting failed with '.$k.'.');
  21000. }
  21001. }
  21002. throw new RuntimeException('Splitting failed with unknown error code.');
  21003. }
  21004. } finally {
  21005. restore_error_handler();
  21006. }
  21007. $str = clone $this;
  21008. if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) {
  21009. foreach ($chunks as &$chunk) {
  21010. $str->string = $chunk[0];
  21011. $chunk[0] = clone $str;
  21012. }
  21013. } else {
  21014. foreach ($chunks as &$chunk) {
  21015. $str->string = $chunk;
  21016. $chunk = clone $str;
  21017. }
  21018. }
  21019. return $chunks;
  21020. }
  21021. public function startsWith($prefix): bool
  21022. {
  21023. if (!\is_array($prefix) && !$prefix instanceof \Traversable) {
  21024. throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
  21025. }
  21026. foreach ($prefix as $prefix) {
  21027. if ($this->startsWith((string) $prefix)) {
  21028. return true;
  21029. }
  21030. }
  21031. return false;
  21032. }
  21033. abstract public function title(bool $allWords = false): self;
  21034. public function toByteString(?string $toEncoding = null): ByteString
  21035. {
  21036. $b = new ByteString();
  21037. $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], true) ? 'UTF-8' : $toEncoding;
  21038. if (null === $toEncoding || $toEncoding === $fromEncoding = $this instanceof AbstractUnicodeString || preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252') {
  21039. $b->string = $this->string;
  21040. return $b;
  21041. }
  21042. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  21043. try {
  21044. try {
  21045. $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8');
  21046. } catch (InvalidArgumentException|\ValueError $e) {
  21047. if (!\function_exists('iconv')) {
  21048. if ($e instanceof \ValueError) {
  21049. throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
  21050. }
  21051. throw $e;
  21052. }
  21053. $b->string = iconv('UTF-8', $toEncoding, $this->string);
  21054. }
  21055. } finally {
  21056. restore_error_handler();
  21057. }
  21058. return $b;
  21059. }
  21060. public function toCodePointString(): CodePointString
  21061. {
  21062. return new CodePointString($this->string);
  21063. }
  21064. public function toString(): string
  21065. {
  21066. return $this->string;
  21067. }
  21068. public function toUnicodeString(): UnicodeString
  21069. {
  21070. return new UnicodeString($this->string);
  21071. }
  21072. abstract public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
  21073. abstract public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
  21074. public function trimPrefix($prefix): self
  21075. {
  21076. if (\is_array($prefix) || $prefix instanceof \Traversable) {
  21077. foreach ($prefix as $s) {
  21078. $t = $this->trimPrefix($s);
  21079. if ($t->string !== $this->string) {
  21080. return $t;
  21081. }
  21082. }
  21083. return clone $this;
  21084. }
  21085. $str = clone $this;
  21086. if ($prefix instanceof self) {
  21087. $prefix = $prefix->string;
  21088. } else {
  21089. $prefix = (string) $prefix;
  21090. }
  21091. if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) {
  21092. $str->string = substr($this->string, \strlen($prefix));
  21093. }
  21094. return $str;
  21095. }
  21096. abstract public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
  21097. public function trimSuffix($suffix): self
  21098. {
  21099. if (\is_array($suffix) || $suffix instanceof \Traversable) {
  21100. foreach ($suffix as $s) {
  21101. $t = $this->trimSuffix($s);
  21102. if ($t->string !== $this->string) {
  21103. return $t;
  21104. }
  21105. }
  21106. return clone $this;
  21107. }
  21108. $str = clone $this;
  21109. if ($suffix instanceof self) {
  21110. $suffix = $suffix->string;
  21111. } else {
  21112. $suffix = (string) $suffix;
  21113. }
  21114. if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) {
  21115. $str->string = substr($this->string, 0, -\strlen($suffix));
  21116. }
  21117. return $str;
  21118. }
  21119. public function truncate(int $length, string $ellipsis = '', bool $cut = true): self
  21120. {
  21121. $stringLength = $this->length();
  21122. if ($stringLength <= $length) {
  21123. return clone $this;
  21124. }
  21125. $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0;
  21126. if ($length < $ellipsisLength) {
  21127. $ellipsisLength = 0;
  21128. }
  21129. if (!$cut) {
  21130. if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
  21131. return clone $this;
  21132. }
  21133. $length += $ellipsisLength;
  21134. }
  21135. $str = $this->slice(0, $length - $ellipsisLength);
  21136. return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
  21137. }
  21138. abstract public function upper(): self;
  21139. abstract public function width(bool $ignoreAnsiDecoration = true): int;
  21140. public function wordwrap(int $width = 75, string $break = "\n", bool $cut = false): self
  21141. {
  21142. $lines = '' !== $break ? $this->split($break) : [clone $this];
  21143. $chars = [];
  21144. $mask = '';
  21145. if (1 === \count($lines) && '' === $lines[0]->string) {
  21146. return $lines[0];
  21147. }
  21148. foreach ($lines as $i => $line) {
  21149. if ($i) {
  21150. $chars[] = $break;
  21151. $mask .= '#';
  21152. }
  21153. foreach ($line->chunk() as $char) {
  21154. $chars[] = $char->string;
  21155. $mask .= ' ' === $char->string ? ' ' : '?';
  21156. }
  21157. }
  21158. $string = '';
  21159. $j = 0;
  21160. $b = $i = -1;
  21161. $mask = wordwrap($mask, $width, '#', $cut);
  21162. while (false !== $b = strpos($mask, '#', $b + 1)) {
  21163. for (++$i; $i < $b; ++$i) {
  21164. $string .= $chars[$j];
  21165. unset($chars[$j++]);
  21166. }
  21167. if ($break === $chars[$j] || ' ' === $chars[$j]) {
  21168. unset($chars[$j++]);
  21169. }
  21170. $string .= $break;
  21171. }
  21172. $str = clone $this;
  21173. $str->string = $string.implode('', $chars);
  21174. return $str;
  21175. }
  21176. public function __sleep(): array
  21177. {
  21178. return ['string'];
  21179. }
  21180. public function __clone()
  21181. {
  21182. $this->ignoreCase = false;
  21183. }
  21184. public function __toString(): string
  21185. {
  21186. return $this->string;
  21187. }
  21188. }
  21189. <?php
  21190. namespace Symfony\Component\String;
  21191. if (!\function_exists(u::class)) {
  21192. function u(?string $string = ''): UnicodeString
  21193. {
  21194. return new UnicodeString($string ?? '');
  21195. }
  21196. }
  21197. if (!\function_exists(b::class)) {
  21198. function b(?string $string = ''): ByteString
  21199. {
  21200. return new ByteString($string ?? '');
  21201. }
  21202. }
  21203. if (!\function_exists(s::class)) {
  21204. function s(?string $string = ''): AbstractString
  21205. {
  21206. $string = $string ?? '';
  21207. return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string);
  21208. }
  21209. }
  21210. <?php
  21211. return [
  21212. [
  21213. 768,
  21214. 879,
  21215. ],
  21216. [
  21217. 1155,
  21218. 1159,
  21219. ],
  21220. [
  21221. 1160,
  21222. 1161,
  21223. ],
  21224. [
  21225. 1425,
  21226. 1469,
  21227. ],
  21228. [
  21229. 1471,
  21230. 1471,
  21231. ],
  21232. [
  21233. 1473,
  21234. 1474,
  21235. ],
  21236. [
  21237. 1476,
  21238. 1477,
  21239. ],
  21240. [
  21241. 1479,
  21242. 1479,
  21243. ],
  21244. [
  21245. 1552,
  21246. 1562,
  21247. ],
  21248. [
  21249. 1611,
  21250. 1631,
  21251. ],
  21252. [
  21253. 1648,
  21254. 1648,
  21255. ],
  21256. [
  21257. 1750,
  21258. 1756,
  21259. ],
  21260. [
  21261. 1759,
  21262. 1764,
  21263. ],
  21264. [
  21265. 1767,
  21266. 1768,
  21267. ],
  21268. [
  21269. 1770,
  21270. 1773,
  21271. ],
  21272. [
  21273. 1809,
  21274. 1809,
  21275. ],
  21276. [
  21277. 1840,
  21278. 1866,
  21279. ],
  21280. [
  21281. 1958,
  21282. 1968,
  21283. ],
  21284. [
  21285. 2027,
  21286. 2035,
  21287. ],
  21288. [
  21289. 2045,
  21290. 2045,
  21291. ],
  21292. [
  21293. 2070,
  21294. 2073,
  21295. ],
  21296. [
  21297. 2075,
  21298. 2083,
  21299. ],
  21300. [
  21301. 2085,
  21302. 2087,
  21303. ],
  21304. [
  21305. 2089,
  21306. 2093,
  21307. ],
  21308. [
  21309. 2137,
  21310. 2139,
  21311. ],
  21312. [
  21313. 2199,
  21314. 2207,
  21315. ],
  21316. [
  21317. 2250,
  21318. 2273,
  21319. ],
  21320. [
  21321. 2275,
  21322. 2306,
  21323. ],
  21324. [
  21325. 2362,
  21326. 2362,
  21327. ],
  21328. [
  21329. 2364,
  21330. 2364,
  21331. ],
  21332. [
  21333. 2369,
  21334. 2376,
  21335. ],
  21336. [
  21337. 2381,
  21338. 2381,
  21339. ],
  21340. [
  21341. 2385,
  21342. 2391,
  21343. ],
  21344. [
  21345. 2402,
  21346. 2403,
  21347. ],
  21348. [
  21349. 2433,
  21350. 2433,
  21351. ],
  21352. [
  21353. 2492,
  21354. 2492,
  21355. ],
  21356. [
  21357. 2497,
  21358. 2500,
  21359. ],
  21360. [
  21361. 2509,
  21362. 2509,
  21363. ],
  21364. [
  21365. 2530,
  21366. 2531,
  21367. ],
  21368. [
  21369. 2558,
  21370. 2558,
  21371. ],
  21372. [
  21373. 2561,
  21374. 2562,
  21375. ],
  21376. [
  21377. 2620,
  21378. 2620,
  21379. ],
  21380. [
  21381. 2625,
  21382. 2626,
  21383. ],
  21384. [
  21385. 2631,
  21386. 2632,
  21387. ],
  21388. [
  21389. 2635,
  21390. 2637,
  21391. ],
  21392. [
  21393. 2641,
  21394. 2641,
  21395. ],
  21396. [
  21397. 2672,
  21398. 2673,
  21399. ],
  21400. [
  21401. 2677,
  21402. 2677,
  21403. ],
  21404. [
  21405. 2689,
  21406. 2690,
  21407. ],
  21408. [
  21409. 2748,
  21410. 2748,
  21411. ],
  21412. [
  21413. 2753,
  21414. 2757,
  21415. ],
  21416. [
  21417. 2759,
  21418. 2760,
  21419. ],
  21420. [
  21421. 2765,
  21422. 2765,
  21423. ],
  21424. [
  21425. 2786,
  21426. 2787,
  21427. ],
  21428. [
  21429. 2810,
  21430. 2815,
  21431. ],
  21432. [
  21433. 2817,
  21434. 2817,
  21435. ],
  21436. [
  21437. 2876,
  21438. 2876,
  21439. ],
  21440. [
  21441. 2879,
  21442. 2879,
  21443. ],
  21444. [
  21445. 2881,
  21446. 2884,
  21447. ],
  21448. [
  21449. 2893,
  21450. 2893,
  21451. ],
  21452. [
  21453. 2901,
  21454. 2902,
  21455. ],
  21456. [
  21457. 2914,
  21458. 2915,
  21459. ],
  21460. [
  21461. 2946,
  21462. 2946,
  21463. ],
  21464. [
  21465. 3008,
  21466. 3008,
  21467. ],
  21468. [
  21469. 3021,
  21470. 3021,
  21471. ],
  21472. [
  21473. 3072,
  21474. 3072,
  21475. ],
  21476. [
  21477. 3076,
  21478. 3076,
  21479. ],
  21480. [
  21481. 3132,
  21482. 3132,
  21483. ],
  21484. [
  21485. 3134,
  21486. 3136,
  21487. ],
  21488. [
  21489. 3142,
  21490. 3144,
  21491. ],
  21492. [
  21493. 3146,
  21494. 3149,
  21495. ],
  21496. [
  21497. 3157,
  21498. 3158,
  21499. ],
  21500. [
  21501. 3170,
  21502. 3171,
  21503. ],
  21504. [
  21505. 3201,
  21506. 3201,
  21507. ],
  21508. [
  21509. 3260,
  21510. 3260,
  21511. ],
  21512. [
  21513. 3263,
  21514. 3263,
  21515. ],
  21516. [
  21517. 3270,
  21518. 3270,
  21519. ],
  21520. [
  21521. 3276,
  21522. 3277,
  21523. ],
  21524. [
  21525. 3298,
  21526. 3299,
  21527. ],
  21528. [
  21529. 3328,
  21530. 3329,
  21531. ],
  21532. [
  21533. 3387,
  21534. 3388,
  21535. ],
  21536. [
  21537. 3393,
  21538. 3396,
  21539. ],
  21540. [
  21541. 3405,
  21542. 3405,
  21543. ],
  21544. [
  21545. 3426,
  21546. 3427,
  21547. ],
  21548. [
  21549. 3457,
  21550. 3457,
  21551. ],
  21552. [
  21553. 3530,
  21554. 3530,
  21555. ],
  21556. [
  21557. 3538,
  21558. 3540,
  21559. ],
  21560. [
  21561. 3542,
  21562. 3542,
  21563. ],
  21564. [
  21565. 3633,
  21566. 3633,
  21567. ],
  21568. [
  21569. 3636,
  21570. 3642,
  21571. ],
  21572. [
  21573. 3655,
  21574. 3662,
  21575. ],
  21576. [
  21577. 3761,
  21578. 3761,
  21579. ],
  21580. [
  21581. 3764,
  21582. 3772,
  21583. ],
  21584. [
  21585. 3784,
  21586. 3790,
  21587. ],
  21588. [
  21589. 3864,
  21590. 3865,
  21591. ],
  21592. [
  21593. 3893,
  21594. 3893,
  21595. ],
  21596. [
  21597. 3895,
  21598. 3895,
  21599. ],
  21600. [
  21601. 3897,
  21602. 3897,
  21603. ],
  21604. [
  21605. 3953,
  21606. 3966,
  21607. ],
  21608. [
  21609. 3968,
  21610. 3972,
  21611. ],
  21612. [
  21613. 3974,
  21614. 3975,
  21615. ],
  21616. [
  21617. 3981,
  21618. 3991,
  21619. ],
  21620. [
  21621. 3993,
  21622. 4028,
  21623. ],
  21624. [
  21625. 4038,
  21626. 4038,
  21627. ],
  21628. [
  21629. 4141,
  21630. 4144,
  21631. ],
  21632. [
  21633. 4146,
  21634. 4151,
  21635. ],
  21636. [
  21637. 4153,
  21638. 4154,
  21639. ],
  21640. [
  21641. 4157,
  21642. 4158,
  21643. ],
  21644. [
  21645. 4184,
  21646. 4185,
  21647. ],
  21648. [
  21649. 4190,
  21650. 4192,
  21651. ],
  21652. [
  21653. 4209,
  21654. 4212,
  21655. ],
  21656. [
  21657. 4226,
  21658. 4226,
  21659. ],
  21660. [
  21661. 4229,
  21662. 4230,
  21663. ],
  21664. [
  21665. 4237,
  21666. 4237,
  21667. ],
  21668. [
  21669. 4253,
  21670. 4253,
  21671. ],
  21672. [
  21673. 4957,
  21674. 4959,
  21675. ],
  21676. [
  21677. 5906,
  21678. 5908,
  21679. ],
  21680. [
  21681. 5938,
  21682. 5939,
  21683. ],
  21684. [
  21685. 5970,
  21686. 5971,
  21687. ],
  21688. [
  21689. 6002,
  21690. 6003,
  21691. ],
  21692. [
  21693. 6068,
  21694. 6069,
  21695. ],
  21696. [
  21697. 6071,
  21698. 6077,
  21699. ],
  21700. [
  21701. 6086,
  21702. 6086,
  21703. ],
  21704. [
  21705. 6089,
  21706. 6099,
  21707. ],
  21708. [
  21709. 6109,
  21710. 6109,
  21711. ],
  21712. [
  21713. 6155,
  21714. 6157,
  21715. ],
  21716. [
  21717. 6159,
  21718. 6159,
  21719. ],
  21720. [
  21721. 6277,
  21722. 6278,
  21723. ],
  21724. [
  21725. 6313,
  21726. 6313,
  21727. ],
  21728. [
  21729. 6432,
  21730. 6434,
  21731. ],
  21732. [
  21733. 6439,
  21734. 6440,
  21735. ],
  21736. [
  21737. 6450,
  21738. 6450,
  21739. ],
  21740. [
  21741. 6457,
  21742. 6459,
  21743. ],
  21744. [
  21745. 6679,
  21746. 6680,
  21747. ],
  21748. [
  21749. 6683,
  21750. 6683,
  21751. ],
  21752. [
  21753. 6742,
  21754. 6742,
  21755. ],
  21756. [
  21757. 6744,
  21758. 6750,
  21759. ],
  21760. [
  21761. 6752,
  21762. 6752,
  21763. ],
  21764. [
  21765. 6754,
  21766. 6754,
  21767. ],
  21768. [
  21769. 6757,
  21770. 6764,
  21771. ],
  21772. [
  21773. 6771,
  21774. 6780,
  21775. ],
  21776. [
  21777. 6783,
  21778. 6783,
  21779. ],
  21780. [
  21781. 6832,
  21782. 6845,
  21783. ],
  21784. [
  21785. 6846,
  21786. 6846,
  21787. ],
  21788. [
  21789. 6847,
  21790. 6862,
  21791. ],
  21792. [
  21793. 6912,
  21794. 6915,
  21795. ],
  21796. [
  21797. 6964,
  21798. 6964,
  21799. ],
  21800. [
  21801. 6966,
  21802. 6970,
  21803. ],
  21804. [
  21805. 6972,
  21806. 6972,
  21807. ],
  21808. [
  21809. 6978,
  21810. 6978,
  21811. ],
  21812. [
  21813. 7019,
  21814. 7027,
  21815. ],
  21816. [
  21817. 7040,
  21818. 7041,
  21819. ],
  21820. [
  21821. 7074,
  21822. 7077,
  21823. ],
  21824. [
  21825. 7080,
  21826. 7081,
  21827. ],
  21828. [
  21829. 7083,
  21830. 7085,
  21831. ],
  21832. [
  21833. 7142,
  21834. 7142,
  21835. ],
  21836. [
  21837. 7144,
  21838. 7145,
  21839. ],
  21840. [
  21841. 7149,
  21842. 7149,
  21843. ],
  21844. [
  21845. 7151,
  21846. 7153,
  21847. ],
  21848. [
  21849. 7212,
  21850. 7219,
  21851. ],
  21852. [
  21853. 7222,
  21854. 7223,
  21855. ],
  21856. [
  21857. 7376,
  21858. 7378,
  21859. ],
  21860. [
  21861. 7380,
  21862. 7392,
  21863. ],
  21864. [
  21865. 7394,
  21866. 7400,
  21867. ],
  21868. [
  21869. 7405,
  21870. 7405,
  21871. ],
  21872. [
  21873. 7412,
  21874. 7412,
  21875. ],
  21876. [
  21877. 7416,
  21878. 7417,
  21879. ],
  21880. [
  21881. 7616,
  21882. 7679,
  21883. ],
  21884. [
  21885. 8400,
  21886. 8412,
  21887. ],
  21888. [
  21889. 8413,
  21890. 8416,
  21891. ],
  21892. [
  21893. 8417,
  21894. 8417,
  21895. ],
  21896. [
  21897. 8418,
  21898. 8420,
  21899. ],
  21900. [
  21901. 8421,
  21902. 8432,
  21903. ],
  21904. [
  21905. 11503,
  21906. 11505,
  21907. ],
  21908. [
  21909. 11647,
  21910. 11647,
  21911. ],
  21912. [
  21913. 11744,
  21914. 11775,
  21915. ],
  21916. [
  21917. 12330,
  21918. 12333,
  21919. ],
  21920. [
  21921. 12441,
  21922. 12442,
  21923. ],
  21924. [
  21925. 42607,
  21926. 42607,
  21927. ],
  21928. [
  21929. 42608,
  21930. 42610,
  21931. ],
  21932. [
  21933. 42612,
  21934. 42621,
  21935. ],
  21936. [
  21937. 42654,
  21938. 42655,
  21939. ],
  21940. [
  21941. 42736,
  21942. 42737,
  21943. ],
  21944. [
  21945. 43010,
  21946. 43010,
  21947. ],
  21948. [
  21949. 43014,
  21950. 43014,
  21951. ],
  21952. [
  21953. 43019,
  21954. 43019,
  21955. ],
  21956. [
  21957. 43045,
  21958. 43046,
  21959. ],
  21960. [
  21961. 43052,
  21962. 43052,
  21963. ],
  21964. [
  21965. 43204,
  21966. 43205,
  21967. ],
  21968. [
  21969. 43232,
  21970. 43249,
  21971. ],
  21972. [
  21973. 43263,
  21974. 43263,
  21975. ],
  21976. [
  21977. 43302,
  21978. 43309,
  21979. ],
  21980. [
  21981. 43335,
  21982. 43345,
  21983. ],
  21984. [
  21985. 43392,
  21986. 43394,
  21987. ],
  21988. [
  21989. 43443,
  21990. 43443,
  21991. ],
  21992. [
  21993. 43446,
  21994. 43449,
  21995. ],
  21996. [
  21997. 43452,
  21998. 43453,
  21999. ],
  22000. [
  22001. 43493,
  22002. 43493,
  22003. ],
  22004. [
  22005. 43561,
  22006. 43566,
  22007. ],
  22008. [
  22009. 43569,
  22010. 43570,
  22011. ],
  22012. [
  22013. 43573,
  22014. 43574,
  22015. ],
  22016. [
  22017. 43587,
  22018. 43587,
  22019. ],
  22020. [
  22021. 43596,
  22022. 43596,
  22023. ],
  22024. [
  22025. 43644,
  22026. 43644,
  22027. ],
  22028. [
  22029. 43696,
  22030. 43696,
  22031. ],
  22032. [
  22033. 43698,
  22034. 43700,
  22035. ],
  22036. [
  22037. 43703,
  22038. 43704,
  22039. ],
  22040. [
  22041. 43710,
  22042. 43711,
  22043. ],
  22044. [
  22045. 43713,
  22046. 43713,
  22047. ],
  22048. [
  22049. 43756,
  22050. 43757,
  22051. ],
  22052. [
  22053. 43766,
  22054. 43766,
  22055. ],
  22056. [
  22057. 44005,
  22058. 44005,
  22059. ],
  22060. [
  22061. 44008,
  22062. 44008,
  22063. ],
  22064. [
  22065. 44013,
  22066. 44013,
  22067. ],
  22068. [
  22069. 64286,
  22070. 64286,
  22071. ],
  22072. [
  22073. 65024,
  22074. 65039,
  22075. ],
  22076. [
  22077. 65056,
  22078. 65071,
  22079. ],
  22080. [
  22081. 66045,
  22082. 66045,
  22083. ],
  22084. [
  22085. 66272,
  22086. 66272,
  22087. ],
  22088. [
  22089. 66422,
  22090. 66426,
  22091. ],
  22092. [
  22093. 68097,
  22094. 68099,
  22095. ],
  22096. [
  22097. 68101,
  22098. 68102,
  22099. ],
  22100. [
  22101. 68108,
  22102. 68111,
  22103. ],
  22104. [
  22105. 68152,
  22106. 68154,
  22107. ],
  22108. [
  22109. 68159,
  22110. 68159,
  22111. ],
  22112. [
  22113. 68325,
  22114. 68326,
  22115. ],
  22116. [
  22117. 68900,
  22118. 68903,
  22119. ],
  22120. [
  22121. 68969,
  22122. 68973,
  22123. ],
  22124. [
  22125. 69291,
  22126. 69292,
  22127. ],
  22128. [
  22129. 69372,
  22130. 69375,
  22131. ],
  22132. [
  22133. 69446,
  22134. 69456,
  22135. ],
  22136. [
  22137. 69506,
  22138. 69509,
  22139. ],
  22140. [
  22141. 69633,
  22142. 69633,
  22143. ],
  22144. [
  22145. 69688,
  22146. 69702,
  22147. ],
  22148. [
  22149. 69744,
  22150. 69744,
  22151. ],
  22152. [
  22153. 69747,
  22154. 69748,
  22155. ],
  22156. [
  22157. 69759,
  22158. 69761,
  22159. ],
  22160. [
  22161. 69811,
  22162. 69814,
  22163. ],
  22164. [
  22165. 69817,
  22166. 69818,
  22167. ],
  22168. [
  22169. 69826,
  22170. 69826,
  22171. ],
  22172. [
  22173. 69888,
  22174. 69890,
  22175. ],
  22176. [
  22177. 69927,
  22178. 69931,
  22179. ],
  22180. [
  22181. 69933,
  22182. 69940,
  22183. ],
  22184. [
  22185. 70003,
  22186. 70003,
  22187. ],
  22188. [
  22189. 70016,
  22190. 70017,
  22191. ],
  22192. [
  22193. 70070,
  22194. 70078,
  22195. ],
  22196. [
  22197. 70089,
  22198. 70092,
  22199. ],
  22200. [
  22201. 70095,
  22202. 70095,
  22203. ],
  22204. [
  22205. 70191,
  22206. 70193,
  22207. ],
  22208. [
  22209. 70196,
  22210. 70196,
  22211. ],
  22212. [
  22213. 70198,
  22214. 70199,
  22215. ],
  22216. [
  22217. 70206,
  22218. 70206,
  22219. ],
  22220. [
  22221. 70209,
  22222. 70209,
  22223. ],
  22224. [
  22225. 70367,
  22226. 70367,
  22227. ],
  22228. [
  22229. 70371,
  22230. 70378,
  22231. ],
  22232. [
  22233. 70400,
  22234. 70401,
  22235. ],
  22236. [
  22237. 70459,
  22238. 70460,
  22239. ],
  22240. [
  22241. 70464,
  22242. 70464,
  22243. ],
  22244. [
  22245. 70502,
  22246. 70508,
  22247. ],
  22248. [
  22249. 70512,
  22250. 70516,
  22251. ],
  22252. [
  22253. 70587,
  22254. 70592,
  22255. ],
  22256. [
  22257. 70606,
  22258. 70606,
  22259. ],
  22260. [
  22261. 70608,
  22262. 70608,
  22263. ],
  22264. [
  22265. 70610,
  22266. 70610,
  22267. ],
  22268. [
  22269. 70625,
  22270. 70626,
  22271. ],
  22272. [
  22273. 70712,
  22274. 70719,
  22275. ],
  22276. [
  22277. 70722,
  22278. 70724,
  22279. ],
  22280. [
  22281. 70726,
  22282. 70726,
  22283. ],
  22284. [
  22285. 70750,
  22286. 70750,
  22287. ],
  22288. [
  22289. 70835,
  22290. 70840,
  22291. ],
  22292. [
  22293. 70842,
  22294. 70842,
  22295. ],
  22296. [
  22297. 70847,
  22298. 70848,
  22299. ],
  22300. [
  22301. 70850,
  22302. 70851,
  22303. ],
  22304. [
  22305. 71090,
  22306. 71093,
  22307. ],
  22308. [
  22309. 71100,
  22310. 71101,
  22311. ],
  22312. [
  22313. 71103,
  22314. 71104,
  22315. ],
  22316. [
  22317. 71132,
  22318. 71133,
  22319. ],
  22320. [
  22321. 71219,
  22322. 71226,
  22323. ],
  22324. [
  22325. 71229,
  22326. 71229,
  22327. ],
  22328. [
  22329. 71231,
  22330. 71232,
  22331. ],
  22332. [
  22333. 71339,
  22334. 71339,
  22335. ],
  22336. [
  22337. 71341,
  22338. 71341,
  22339. ],
  22340. [
  22341. 71344,
  22342. 71349,
  22343. ],
  22344. [
  22345. 71351,
  22346. 71351,
  22347. ],
  22348. [
  22349. 71453,
  22350. 71453,
  22351. ],
  22352. [
  22353. 71455,
  22354. 71455,
  22355. ],
  22356. [
  22357. 71458,
  22358. 71461,
  22359. ],
  22360. [
  22361. 71463,
  22362. 71467,
  22363. ],
  22364. [
  22365. 71727,
  22366. 71735,
  22367. ],
  22368. [
  22369. 71737,
  22370. 71738,
  22371. ],
  22372. [
  22373. 71995,
  22374. 71996,
  22375. ],
  22376. [
  22377. 71998,
  22378. 71998,
  22379. ],
  22380. [
  22381. 72003,
  22382. 72003,
  22383. ],
  22384. [
  22385. 72148,
  22386. 72151,
  22387. ],
  22388. [
  22389. 72154,
  22390. 72155,
  22391. ],
  22392. [
  22393. 72160,
  22394. 72160,
  22395. ],
  22396. [
  22397. 72193,
  22398. 72202,
  22399. ],
  22400. [
  22401. 72243,
  22402. 72248,
  22403. ],
  22404. [
  22405. 72251,
  22406. 72254,
  22407. ],
  22408. [
  22409. 72263,
  22410. 72263,
  22411. ],
  22412. [
  22413. 72273,
  22414. 72278,
  22415. ],
  22416. [
  22417. 72281,
  22418. 72283,
  22419. ],
  22420. [
  22421. 72330,
  22422. 72342,
  22423. ],
  22424. [
  22425. 72344,
  22426. 72345,
  22427. ],
  22428. [
  22429. 72752,
  22430. 72758,
  22431. ],
  22432. [
  22433. 72760,
  22434. 72765,
  22435. ],
  22436. [
  22437. 72767,
  22438. 72767,
  22439. ],
  22440. [
  22441. 72850,
  22442. 72871,
  22443. ],
  22444. [
  22445. 72874,
  22446. 72880,
  22447. ],
  22448. [
  22449. 72882,
  22450. 72883,
  22451. ],
  22452. [
  22453. 72885,
  22454. 72886,
  22455. ],
  22456. [
  22457. 73009,
  22458. 73014,
  22459. ],
  22460. [
  22461. 73018,
  22462. 73018,
  22463. ],
  22464. [
  22465. 73020,
  22466. 73021,
  22467. ],
  22468. [
  22469. 73023,
  22470. 73029,
  22471. ],
  22472. [
  22473. 73031,
  22474. 73031,
  22475. ],
  22476. [
  22477. 73104,
  22478. 73105,
  22479. ],
  22480. [
  22481. 73109,
  22482. 73109,
  22483. ],
  22484. [
  22485. 73111,
  22486. 73111,
  22487. ],
  22488. [
  22489. 73459,
  22490. 73460,
  22491. ],
  22492. [
  22493. 73472,
  22494. 73473,
  22495. ],
  22496. [
  22497. 73526,
  22498. 73530,
  22499. ],
  22500. [
  22501. 73536,
  22502. 73536,
  22503. ],
  22504. [
  22505. 73538,
  22506. 73538,
  22507. ],
  22508. [
  22509. 73562,
  22510. 73562,
  22511. ],
  22512. [
  22513. 78912,
  22514. 78912,
  22515. ],
  22516. [
  22517. 78919,
  22518. 78933,
  22519. ],
  22520. [
  22521. 90398,
  22522. 90409,
  22523. ],
  22524. [
  22525. 90413,
  22526. 90415,
  22527. ],
  22528. [
  22529. 92912,
  22530. 92916,
  22531. ],
  22532. [
  22533. 92976,
  22534. 92982,
  22535. ],
  22536. [
  22537. 94031,
  22538. 94031,
  22539. ],
  22540. [
  22541. 94095,
  22542. 94098,
  22543. ],
  22544. [
  22545. 94180,
  22546. 94180,
  22547. ],
  22548. [
  22549. 113821,
  22550. 113822,
  22551. ],
  22552. [
  22553. 118528,
  22554. 118573,
  22555. ],
  22556. [
  22557. 118576,
  22558. 118598,
  22559. ],
  22560. [
  22561. 119143,
  22562. 119145,
  22563. ],
  22564. [
  22565. 119163,
  22566. 119170,
  22567. ],
  22568. [
  22569. 119173,
  22570. 119179,
  22571. ],
  22572. [
  22573. 119210,
  22574. 119213,
  22575. ],
  22576. [
  22577. 119362,
  22578. 119364,
  22579. ],
  22580. [
  22581. 121344,
  22582. 121398,
  22583. ],
  22584. [
  22585. 121403,
  22586. 121452,
  22587. ],
  22588. [
  22589. 121461,
  22590. 121461,
  22591. ],
  22592. [
  22593. 121476,
  22594. 121476,
  22595. ],
  22596. [
  22597. 121499,
  22598. 121503,
  22599. ],
  22600. [
  22601. 121505,
  22602. 121519,
  22603. ],
  22604. [
  22605. 122880,
  22606. 122886,
  22607. ],
  22608. [
  22609. 122888,
  22610. 122904,
  22611. ],
  22612. [
  22613. 122907,
  22614. 122913,
  22615. ],
  22616. [
  22617. 122915,
  22618. 122916,
  22619. ],
  22620. [
  22621. 122918,
  22622. 122922,
  22623. ],
  22624. [
  22625. 123023,
  22626. 123023,
  22627. ],
  22628. [
  22629. 123184,
  22630. 123190,
  22631. ],
  22632. [
  22633. 123566,
  22634. 123566,
  22635. ],
  22636. [
  22637. 123628,
  22638. 123631,
  22639. ],
  22640. [
  22641. 124140,
  22642. 124143,
  22643. ],
  22644. [
  22645. 124398,
  22646. 124399,
  22647. ],
  22648. [
  22649. 125136,
  22650. 125142,
  22651. ],
  22652. [
  22653. 125252,
  22654. 125258,
  22655. ],
  22656. [
  22657. 917760,
  22658. 917999,
  22659. ],
  22660. ];
  22661. <?php
  22662. return [
  22663. [
  22664. 4352,
  22665. 4447,
  22666. ],
  22667. [
  22668. 8986,
  22669. 8987,
  22670. ],
  22671. [
  22672. 9001,
  22673. 9001,
  22674. ],
  22675. [
  22676. 9002,
  22677. 9002,
  22678. ],
  22679. [
  22680. 9193,
  22681. 9196,
  22682. ],
  22683. [
  22684. 9200,
  22685. 9200,
  22686. ],
  22687. [
  22688. 9203,
  22689. 9203,
  22690. ],
  22691. [
  22692. 9725,
  22693. 9726,
  22694. ],
  22695. [
  22696. 9748,
  22697. 9749,
  22698. ],
  22699. [
  22700. 9776,
  22701. 9783,
  22702. ],
  22703. [
  22704. 9800,
  22705. 9811,
  22706. ],
  22707. [
  22708. 9855,
  22709. 9855,
  22710. ],
  22711. [
  22712. 9866,
  22713. 9871,
  22714. ],
  22715. [
  22716. 9875,
  22717. 9875,
  22718. ],
  22719. [
  22720. 9889,
  22721. 9889,
  22722. ],
  22723. [
  22724. 9898,
  22725. 9899,
  22726. ],
  22727. [
  22728. 9917,
  22729. 9918,
  22730. ],
  22731. [
  22732. 9924,
  22733. 9925,
  22734. ],
  22735. [
  22736. 9934,
  22737. 9934,
  22738. ],
  22739. [
  22740. 9940,
  22741. 9940,
  22742. ],
  22743. [
  22744. 9962,
  22745. 9962,
  22746. ],
  22747. [
  22748. 9970,
  22749. 9971,
  22750. ],
  22751. [
  22752. 9973,
  22753. 9973,
  22754. ],
  22755. [
  22756. 9978,
  22757. 9978,
  22758. ],
  22759. [
  22760. 9981,
  22761. 9981,
  22762. ],
  22763. [
  22764. 9989,
  22765. 9989,
  22766. ],
  22767. [
  22768. 9994,
  22769. 9995,
  22770. ],
  22771. [
  22772. 10024,
  22773. 10024,
  22774. ],
  22775. [
  22776. 10060,
  22777. 10060,
  22778. ],
  22779. [
  22780. 10062,
  22781. 10062,
  22782. ],
  22783. [
  22784. 10067,
  22785. 10069,
  22786. ],
  22787. [
  22788. 10071,
  22789. 10071,
  22790. ],
  22791. [
  22792. 10133,
  22793. 10135,
  22794. ],
  22795. [
  22796. 10160,
  22797. 10160,
  22798. ],
  22799. [
  22800. 10175,
  22801. 10175,
  22802. ],
  22803. [
  22804. 11035,
  22805. 11036,
  22806. ],
  22807. [
  22808. 11088,
  22809. 11088,
  22810. ],
  22811. [
  22812. 11093,
  22813. 11093,
  22814. ],
  22815. [
  22816. 11904,
  22817. 11929,
  22818. ],
  22819. [
  22820. 11931,
  22821. 12019,
  22822. ],
  22823. [
  22824. 12032,
  22825. 12245,
  22826. ],
  22827. [
  22828. 12272,
  22829. 12287,
  22830. ],
  22831. [
  22832. 12288,
  22833. 12288,
  22834. ],
  22835. [
  22836. 12289,
  22837. 12291,
  22838. ],
  22839. [
  22840. 12292,
  22841. 12292,
  22842. ],
  22843. [
  22844. 12293,
  22845. 12293,
  22846. ],
  22847. [
  22848. 12294,
  22849. 12294,
  22850. ],
  22851. [
  22852. 12295,
  22853. 12295,
  22854. ],
  22855. [
  22856. 12296,
  22857. 12296,
  22858. ],
  22859. [
  22860. 12297,
  22861. 12297,
  22862. ],
  22863. [
  22864. 12298,
  22865. 12298,
  22866. ],
  22867. [
  22868. 12299,
  22869. 12299,
  22870. ],
  22871. [
  22872. 12300,
  22873. 12300,
  22874. ],
  22875. [
  22876. 12301,
  22877. 12301,
  22878. ],
  22879. [
  22880. 12302,
  22881. 12302,
  22882. ],
  22883. [
  22884. 12303,
  22885. 12303,
  22886. ],
  22887. [
  22888. 12304,
  22889. 12304,
  22890. ],
  22891. [
  22892. 12305,
  22893. 12305,
  22894. ],
  22895. [
  22896. 12306,
  22897. 12307,
  22898. ],
  22899. [
  22900. 12308,
  22901. 12308,
  22902. ],
  22903. [
  22904. 12309,
  22905. 12309,
  22906. ],
  22907. [
  22908. 12310,
  22909. 12310,
  22910. ],
  22911. [
  22912. 12311,
  22913. 12311,
  22914. ],
  22915. [
  22916. 12312,
  22917. 12312,
  22918. ],
  22919. [
  22920. 12313,
  22921. 12313,
  22922. ],
  22923. [
  22924. 12314,
  22925. 12314,
  22926. ],
  22927. [
  22928. 12315,
  22929. 12315,
  22930. ],
  22931. [
  22932. 12316,
  22933. 12316,
  22934. ],
  22935. [
  22936. 12317,
  22937. 12317,
  22938. ],
  22939. [
  22940. 12318,
  22941. 12319,
  22942. ],
  22943. [
  22944. 12320,
  22945. 12320,
  22946. ],
  22947. [
  22948. 12321,
  22949. 12329,
  22950. ],
  22951. [
  22952. 12330,
  22953. 12333,
  22954. ],
  22955. [
  22956. 12334,
  22957. 12335,
  22958. ],
  22959. [
  22960. 12336,
  22961. 12336,
  22962. ],
  22963. [
  22964. 12337,
  22965. 12341,
  22966. ],
  22967. [
  22968. 12342,
  22969. 12343,
  22970. ],
  22971. [
  22972. 12344,
  22973. 12346,
  22974. ],
  22975. [
  22976. 12347,
  22977. 12347,
  22978. ],
  22979. [
  22980. 12348,
  22981. 12348,
  22982. ],
  22983. [
  22984. 12349,
  22985. 12349,
  22986. ],
  22987. [
  22988. 12350,
  22989. 12350,
  22990. ],
  22991. [
  22992. 12353,
  22993. 12438,
  22994. ],
  22995. [
  22996. 12441,
  22997. 12442,
  22998. ],
  22999. [
  23000. 12443,
  23001. 12444,
  23002. ],
  23003. [
  23004. 12445,
  23005. 12446,
  23006. ],
  23007. [
  23008. 12447,
  23009. 12447,
  23010. ],
  23011. [
  23012. 12448,
  23013. 12448,
  23014. ],
  23015. [
  23016. 12449,
  23017. 12538,
  23018. ],
  23019. [
  23020. 12539,
  23021. 12539,
  23022. ],
  23023. [
  23024. 12540,
  23025. 12542,
  23026. ],
  23027. [
  23028. 12543,
  23029. 12543,
  23030. ],
  23031. [
  23032. 12549,
  23033. 12591,
  23034. ],
  23035. [
  23036. 12593,
  23037. 12686,
  23038. ],
  23039. [
  23040. 12688,
  23041. 12689,
  23042. ],
  23043. [
  23044. 12690,
  23045. 12693,
  23046. ],
  23047. [
  23048. 12694,
  23049. 12703,
  23050. ],
  23051. [
  23052. 12704,
  23053. 12735,
  23054. ],
  23055. [
  23056. 12736,
  23057. 12773,
  23058. ],
  23059. [
  23060. 12783,
  23061. 12783,
  23062. ],
  23063. [
  23064. 12784,
  23065. 12799,
  23066. ],
  23067. [
  23068. 12800,
  23069. 12830,
  23070. ],
  23071. [
  23072. 12832,
  23073. 12841,
  23074. ],
  23075. [
  23076. 12842,
  23077. 12871,
  23078. ],
  23079. [
  23080. 12880,
  23081. 12880,
  23082. ],
  23083. [
  23084. 12881,
  23085. 12895,
  23086. ],
  23087. [
  23088. 12896,
  23089. 12927,
  23090. ],
  23091. [
  23092. 12928,
  23093. 12937,
  23094. ],
  23095. [
  23096. 12938,
  23097. 12976,
  23098. ],
  23099. [
  23100. 12977,
  23101. 12991,
  23102. ],
  23103. [
  23104. 12992,
  23105. 13055,
  23106. ],
  23107. [
  23108. 13056,
  23109. 13311,
  23110. ],
  23111. [
  23112. 13312,
  23113. 19903,
  23114. ],
  23115. [
  23116. 19904,
  23117. 19967,
  23118. ],
  23119. [
  23120. 19968,
  23121. 40959,
  23122. ],
  23123. [
  23124. 40960,
  23125. 40980,
  23126. ],
  23127. [
  23128. 40981,
  23129. 40981,
  23130. ],
  23131. [
  23132. 40982,
  23133. 42124,
  23134. ],
  23135. [
  23136. 42128,
  23137. 42182,
  23138. ],
  23139. [
  23140. 43360,
  23141. 43388,
  23142. ],
  23143. [
  23144. 44032,
  23145. 55203,
  23146. ],
  23147. [
  23148. 63744,
  23149. 64109,
  23150. ],
  23151. [
  23152. 64110,
  23153. 64111,
  23154. ],
  23155. [
  23156. 64112,
  23157. 64217,
  23158. ],
  23159. [
  23160. 64218,
  23161. 64255,
  23162. ],
  23163. [
  23164. 65040,
  23165. 65046,
  23166. ],
  23167. [
  23168. 65047,
  23169. 65047,
  23170. ],
  23171. [
  23172. 65048,
  23173. 65048,
  23174. ],
  23175. [
  23176. 65049,
  23177. 65049,
  23178. ],
  23179. [
  23180. 65072,
  23181. 65072,
  23182. ],
  23183. [
  23184. 65073,
  23185. 65074,
  23186. ],
  23187. [
  23188. 65075,
  23189. 65076,
  23190. ],
  23191. [
  23192. 65077,
  23193. 65077,
  23194. ],
  23195. [
  23196. 65078,
  23197. 65078,
  23198. ],
  23199. [
  23200. 65079,
  23201. 65079,
  23202. ],
  23203. [
  23204. 65080,
  23205. 65080,
  23206. ],
  23207. [
  23208. 65081,
  23209. 65081,
  23210. ],
  23211. [
  23212. 65082,
  23213. 65082,
  23214. ],
  23215. [
  23216. 65083,
  23217. 65083,
  23218. ],
  23219. [
  23220. 65084,
  23221. 65084,
  23222. ],
  23223. [
  23224. 65085,
  23225. 65085,
  23226. ],
  23227. [
  23228. 65086,
  23229. 65086,
  23230. ],
  23231. [
  23232. 65087,
  23233. 65087,
  23234. ],
  23235. [
  23236. 65088,
  23237. 65088,
  23238. ],
  23239. [
  23240. 65089,
  23241. 65089,
  23242. ],
  23243. [
  23244. 65090,
  23245. 65090,
  23246. ],
  23247. [
  23248. 65091,
  23249. 65091,
  23250. ],
  23251. [
  23252. 65092,
  23253. 65092,
  23254. ],
  23255. [
  23256. 65093,
  23257. 65094,
  23258. ],
  23259. [
  23260. 65095,
  23261. 65095,
  23262. ],
  23263. [
  23264. 65096,
  23265. 65096,
  23266. ],
  23267. [
  23268. 65097,
  23269. 65100,
  23270. ],
  23271. [
  23272. 65101,
  23273. 65103,
  23274. ],
  23275. [
  23276. 65104,
  23277. 65106,
  23278. ],
  23279. [
  23280. 65108,
  23281. 65111,
  23282. ],
  23283. [
  23284. 65112,
  23285. 65112,
  23286. ],
  23287. [
  23288. 65113,
  23289. 65113,
  23290. ],
  23291. [
  23292. 65114,
  23293. 65114,
  23294. ],
  23295. [
  23296. 65115,
  23297. 65115,
  23298. ],
  23299. [
  23300. 65116,
  23301. 65116,
  23302. ],
  23303. [
  23304. 65117,
  23305. 65117,
  23306. ],
  23307. [
  23308. 65118,
  23309. 65118,
  23310. ],
  23311. [
  23312. 65119,
  23313. 65121,
  23314. ],
  23315. [
  23316. 65122,
  23317. 65122,
  23318. ],
  23319. [
  23320. 65123,
  23321. 65123,
  23322. ],
  23323. [
  23324. 65124,
  23325. 65126,
  23326. ],
  23327. [
  23328. 65128,
  23329. 65128,
  23330. ],
  23331. [
  23332. 65129,
  23333. 65129,
  23334. ],
  23335. [
  23336. 65130,
  23337. 65131,
  23338. ],
  23339. [
  23340. 65281,
  23341. 65283,
  23342. ],
  23343. [
  23344. 65284,
  23345. 65284,
  23346. ],
  23347. [
  23348. 65285,
  23349. 65287,
  23350. ],
  23351. [
  23352. 65288,
  23353. 65288,
  23354. ],
  23355. [
  23356. 65289,
  23357. 65289,
  23358. ],
  23359. [
  23360. 65290,
  23361. 65290,
  23362. ],
  23363. [
  23364. 65291,
  23365. 65291,
  23366. ],
  23367. [
  23368. 65292,
  23369. 65292,
  23370. ],
  23371. [
  23372. 65293,
  23373. 65293,
  23374. ],
  23375. [
  23376. 65294,
  23377. 65295,
  23378. ],
  23379. [
  23380. 65296,
  23381. 65305,
  23382. ],
  23383. [
  23384. 65306,
  23385. 65307,
  23386. ],
  23387. [
  23388. 65308,
  23389. 65310,
  23390. ],
  23391. [
  23392. 65311,
  23393. 65312,
  23394. ],
  23395. [
  23396. 65313,
  23397. 65338,
  23398. ],
  23399. [
  23400. 65339,
  23401. 65339,
  23402. ],
  23403. [
  23404. 65340,
  23405. 65340,
  23406. ],
  23407. [
  23408. 65341,
  23409. 65341,
  23410. ],
  23411. [
  23412. 65342,
  23413. 65342,
  23414. ],
  23415. [
  23416. 65343,
  23417. 65343,
  23418. ],
  23419. [
  23420. 65344,
  23421. 65344,
  23422. ],
  23423. [
  23424. 65345,
  23425. 65370,
  23426. ],
  23427. [
  23428. 65371,
  23429. 65371,
  23430. ],
  23431. [
  23432. 65372,
  23433. 65372,
  23434. ],
  23435. [
  23436. 65373,
  23437. 65373,
  23438. ],
  23439. [
  23440. 65374,
  23441. 65374,
  23442. ],
  23443. [
  23444. 65375,
  23445. 65375,
  23446. ],
  23447. [
  23448. 65376,
  23449. 65376,
  23450. ],
  23451. [
  23452. 65504,
  23453. 65505,
  23454. ],
  23455. [
  23456. 65506,
  23457. 65506,
  23458. ],
  23459. [
  23460. 65507,
  23461. 65507,
  23462. ],
  23463. [
  23464. 65508,
  23465. 65508,
  23466. ],
  23467. [
  23468. 65509,
  23469. 65510,
  23470. ],
  23471. [
  23472. 94176,
  23473. 94177,
  23474. ],
  23475. [
  23476. 94178,
  23477. 94178,
  23478. ],
  23479. [
  23480. 94179,
  23481. 94179,
  23482. ],
  23483. [
  23484. 94180,
  23485. 94180,
  23486. ],
  23487. [
  23488. 94192,
  23489. 94193,
  23490. ],
  23491. [
  23492. 94208,
  23493. 100343,
  23494. ],
  23495. [
  23496. 100352,
  23497. 101119,
  23498. ],
  23499. [
  23500. 101120,
  23501. 101589,
  23502. ],
  23503. [
  23504. 101631,
  23505. 101631,
  23506. ],
  23507. [
  23508. 101632,
  23509. 101640,
  23510. ],
  23511. [
  23512. 110576,
  23513. 110579,
  23514. ],
  23515. [
  23516. 110581,
  23517. 110587,
  23518. ],
  23519. [
  23520. 110589,
  23521. 110590,
  23522. ],
  23523. [
  23524. 110592,
  23525. 110847,
  23526. ],
  23527. [
  23528. 110848,
  23529. 110882,
  23530. ],
  23531. [
  23532. 110898,
  23533. 110898,
  23534. ],
  23535. [
  23536. 110928,
  23537. 110930,
  23538. ],
  23539. [
  23540. 110933,
  23541. 110933,
  23542. ],
  23543. [
  23544. 110948,
  23545. 110951,
  23546. ],
  23547. [
  23548. 110960,
  23549. 111355,
  23550. ],
  23551. [
  23552. 119552,
  23553. 119638,
  23554. ],
  23555. [
  23556. 119648,
  23557. 119670,
  23558. ],
  23559. [
  23560. 126980,
  23561. 126980,
  23562. ],
  23563. [
  23564. 127183,
  23565. 127183,
  23566. ],
  23567. [
  23568. 127374,
  23569. 127374,
  23570. ],
  23571. [
  23572. 127377,
  23573. 127386,
  23574. ],
  23575. [
  23576. 127488,
  23577. 127490,
  23578. ],
  23579. [
  23580. 127504,
  23581. 127547,
  23582. ],
  23583. [
  23584. 127552,
  23585. 127560,
  23586. ],
  23587. [
  23588. 127568,
  23589. 127569,
  23590. ],
  23591. [
  23592. 127584,
  23593. 127589,
  23594. ],
  23595. [
  23596. 127744,
  23597. 127776,
  23598. ],
  23599. [
  23600. 127789,
  23601. 127797,
  23602. ],
  23603. [
  23604. 127799,
  23605. 127868,
  23606. ],
  23607. [
  23608. 127870,
  23609. 127891,
  23610. ],
  23611. [
  23612. 127904,
  23613. 127946,
  23614. ],
  23615. [
  23616. 127951,
  23617. 127955,
  23618. ],
  23619. [
  23620. 127968,
  23621. 127984,
  23622. ],
  23623. [
  23624. 127988,
  23625. 127988,
  23626. ],
  23627. [
  23628. 127992,
  23629. 127994,
  23630. ],
  23631. [
  23632. 127995,
  23633. 127999,
  23634. ],
  23635. [
  23636. 128000,
  23637. 128062,
  23638. ],
  23639. [
  23640. 128064,
  23641. 128064,
  23642. ],
  23643. [
  23644. 128066,
  23645. 128252,
  23646. ],
  23647. [
  23648. 128255,
  23649. 128317,
  23650. ],
  23651. [
  23652. 128331,
  23653. 128334,
  23654. ],
  23655. [
  23656. 128336,
  23657. 128359,
  23658. ],
  23659. [
  23660. 128378,
  23661. 128378,
  23662. ],
  23663. [
  23664. 128405,
  23665. 128406,
  23666. ],
  23667. [
  23668. 128420,
  23669. 128420,
  23670. ],
  23671. [
  23672. 128507,
  23673. 128511,
  23674. ],
  23675. [
  23676. 128512,
  23677. 128591,
  23678. ],
  23679. [
  23680. 128640,
  23681. 128709,
  23682. ],
  23683. [
  23684. 128716,
  23685. 128716,
  23686. ],
  23687. [
  23688. 128720,
  23689. 128722,
  23690. ],
  23691. [
  23692. 128725,
  23693. 128727,
  23694. ],
  23695. [
  23696. 128732,
  23697. 128735,
  23698. ],
  23699. [
  23700. 128747,
  23701. 128748,
  23702. ],
  23703. [
  23704. 128756,
  23705. 128764,
  23706. ],
  23707. [
  23708. 128992,
  23709. 129003,
  23710. ],
  23711. [
  23712. 129008,
  23713. 129008,
  23714. ],
  23715. [
  23716. 129292,
  23717. 129338,
  23718. ],
  23719. [
  23720. 129340,
  23721. 129349,
  23722. ],
  23723. [
  23724. 129351,
  23725. 129535,
  23726. ],
  23727. [
  23728. 129648,
  23729. 129660,
  23730. ],
  23731. [
  23732. 129664,
  23733. 129673,
  23734. ],
  23735. [
  23736. 129679,
  23737. 129734,
  23738. ],
  23739. [
  23740. 129742,
  23741. 129756,
  23742. ],
  23743. [
  23744. 129759,
  23745. 129769,
  23746. ],
  23747. [
  23748. 129776,
  23749. 129784,
  23750. ],
  23751. [
  23752. 131072,
  23753. 173791,
  23754. ],
  23755. [
  23756. 173792,
  23757. 173823,
  23758. ],
  23759. [
  23760. 173824,
  23761. 177977,
  23762. ],
  23763. [
  23764. 177978,
  23765. 177983,
  23766. ],
  23767. [
  23768. 177984,
  23769. 178205,
  23770. ],
  23771. [
  23772. 178206,
  23773. 178207,
  23774. ],
  23775. [
  23776. 178208,
  23777. 183969,
  23778. ],
  23779. [
  23780. 183970,
  23781. 183983,
  23782. ],
  23783. [
  23784. 183984,
  23785. 191456,
  23786. ],
  23787. [
  23788. 191457,
  23789. 191471,
  23790. ],
  23791. [
  23792. 191472,
  23793. 192093,
  23794. ],
  23795. [
  23796. 192094,
  23797. 194559,
  23798. ],
  23799. [
  23800. 194560,
  23801. 195101,
  23802. ],
  23803. [
  23804. 195102,
  23805. 195103,
  23806. ],
  23807. [
  23808. 195104,
  23809. 196605,
  23810. ],
  23811. [
  23812. 196608,
  23813. 201546,
  23814. ],
  23815. [
  23816. 201547,
  23817. 201551,
  23818. ],
  23819. [
  23820. 201552,
  23821. 205743,
  23822. ],
  23823. [
  23824. 205744,
  23825. 262141,
  23826. ],
  23827. ];
  23828. <?php
  23829. namespace Symfony\Component\String\Inflector;
  23830. final class FrenchInflector implements InflectorInterface
  23831. {
  23832. private const PLURALIZE_REGEXP = [
  23833. ['/(s|x|z)$/i', '\1'],
  23834. ['/(eau)$/i', '\1x'],
  23835. ['/^(landau)$/i', '\1s'],
  23836. ['/(au)$/i', '\1x'],
  23837. ['/^(pneu|bleu|émeu)$/i', '\1s'],
  23838. ['/(eu)$/i', '\1x'],
  23839. ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\1s'],
  23840. ['/al$/i', '\1aux'],
  23841. ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\1aux'],
  23842. ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\1oux'],
  23843. ['/^(cinquante|soixante|mille)$/i', '\1'],
  23844. ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'mes\2s'],
  23845. ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Mes\2s'],
  23846. ];
  23847. private const SINGULARIZE_REGEXP = [
  23848. ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\1ail'],
  23849. ['/(eau)x$/i', '\1'],
  23850. ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\1al'],
  23851. ['/(au)x$/i', '\1'],
  23852. ['/(eu)x$/i', '\1'],
  23853. ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\1ou'],
  23854. ['/^mes(dame|demoiselle)s$/', 'ma\1'],
  23855. ['/^Mes(dame|demoiselle)s$/', 'Ma\1'],
  23856. ['/^mes(sieur|seigneur)s$/', 'mon\1'],
  23857. ['/^Mes(sieur|seigneur)s$/', 'Mon\1'],
  23858. ['/s$/i', ''],
  23859. ];
  23860. private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i';
  23861. public function singularize(string $plural): array
  23862. {
  23863. if ($this->isInflectedWord($plural)) {
  23864. return [$plural];
  23865. }
  23866. foreach (self::SINGULARIZE_REGEXP as $rule) {
  23867. [$regexp, $replace] = $rule;
  23868. if (1 === preg_match($regexp, $plural)) {
  23869. return [preg_replace($regexp, $replace, $plural)];
  23870. }
  23871. }
  23872. return [$plural];
  23873. }
  23874. public function pluralize(string $singular): array
  23875. {
  23876. if ($this->isInflectedWord($singular)) {
  23877. return [$singular];
  23878. }
  23879. foreach (self::PLURALIZE_REGEXP as $rule) {
  23880. [$regexp, $replace] = $rule;
  23881. if (1 === preg_match($regexp, $singular)) {
  23882. return [preg_replace($regexp, $replace, $singular)];
  23883. }
  23884. }
  23885. return [$singular.'s'];
  23886. }
  23887. private function isInflectedWord(string $word): bool
  23888. {
  23889. return 1 === preg_match(self::UNINFLECTED, $word);
  23890. }
  23891. }
  23892. <?php
  23893. namespace Symfony\Component\String\Inflector;
  23894. interface InflectorInterface
  23895. {
  23896. public function singularize(string $plural): array;
  23897. public function pluralize(string $singular): array;
  23898. }
  23899. <?php
  23900. namespace Symfony\Component\String\Inflector;
  23901. final class EnglishInflector implements InflectorInterface
  23902. {
  23903. private const PLURAL_MAP = [
  23904. ['airetcab', 8, true, true, 'bacterium'],
  23905. ['aroproc', 7, true, true, 'corpus'],
  23906. ['airetirc', 8, true, true, 'criterion'],
  23907. ['alucirruc', 9, true, true, 'curriculum'],
  23908. ['areneg', 6, true, true, 'genus'],
  23909. ['aidem', 5, true, true, 'medium'],
  23910. ['adnaromem', 9, true, true, 'memorandum'],
  23911. ['anemonehp', 9, true, true, 'phenomenon'],
  23912. ['atarts', 6, true, true, 'stratum'],
  23913. ['ea', 2, true, true, 'a'],
  23914. ['secivres', 8, true, true, 'service'],
  23915. ['eci', 3, false, true, 'ouse'],
  23916. ['esee', 4, false, true, 'oose'],
  23917. ['i', 1, true, true, 'us'],
  23918. ['nem', 3, true, true, 'man'],
  23919. ['nerdlihc', 8, true, true, 'child'],
  23920. ['nexo', 4, false, false, 'ox'],
  23921. ['seci', 4, false, true, ['ex', 'ix', 'ice']],
  23922. ['sedoc', 5, false, true, 'code'],
  23923. ['seifles', 7, true, true, 'selfie'],
  23924. ['seibmoz', 7, true, true, 'zombie'],
  23925. ['seivom', 6, true, true, 'movie'],
  23926. ['seman', 5, true, false, 'name'],
  23927. ['sesutcep', 8, true, true, 'pectus'],
  23928. ['teef', 4, true, true, 'foot'],
  23929. ['eseeg', 5, true, true, 'goose'],
  23930. ['hteet', 5, true, true, 'tooth'],
  23931. ['swen', 4, true, true, 'news'],
  23932. ['seires', 6, true, true, 'series'],
  23933. ['sei', 3, false, true, 'y'],
  23934. ['sess', 4, true, false, 'ss'],
  23935. ['sesutats', 8, true, true, 'status'],
  23936. ['sel', 3, true, true, 'le'],
  23937. ['ses', 3, true, true, ['s', 'se', 'sis']],
  23938. ['sevit', 5, true, true, 'tive'],
  23939. ['sevird', 6, false, true, 'drive'],
  23940. ['sevi', 4, false, true, 'ife'],
  23941. ['sevom', 5, true, true, 'move'],
  23942. ['sev', 3, true, true, ['f', 've', 'ff']],
  23943. ['sexa', 4, false, false, ['ax', 'axe', 'axis']],
  23944. ['sex', 3, true, false, 'x'],
  23945. ['sezz', 4, true, false, 'z'],
  23946. ['suae', 4, false, true, 'eau'],
  23947. ['see', 3, true, true, 'ee'],
  23948. ['segd', 4, true, true, 'dge'],
  23949. ['se', 2, true, true, ['', 'e']],
  23950. ['sutats', 6, true, true, 'status'],
  23951. ['s', 1, true, true, ''],
  23952. ['xuae', 4, false, true, 'eau'],
  23953. ['elpoep', 6, true, true, 'person'],
  23954. ];
  23955. private const SINGULAR_MAP = [
  23956. ['sixa', 4, false, false, 'axes'],
  23957. ['airetirc', 8, false, false, 'criterion'],
  23958. ['aluben', 6, false, false, 'nebulae'],
  23959. ['dlihc', 5, true, true, 'children'],
  23960. ['eci', 3, false, true, 'ices'],
  23961. ['ecivres', 7, true, true, 'services'],
  23962. ['efi', 3, false, true, 'ives'],
  23963. ['eifles', 6, true, true, 'selfies'],
  23964. ['eivom', 5, true, true, 'movies'],
  23965. ['esuol', 5, false, true, 'lice'],
  23966. ['esuom', 5, false, true, 'mice'],
  23967. ['esoo', 4, false, true, 'eese'],
  23968. ['es', 2, true, true, 'ses'],
  23969. ['esoog', 5, true, true, 'geese'],
  23970. ['ev', 2, true, true, 'ves'],
  23971. ['evird', 5, false, true, 'drives'],
  23972. ['evit', 4, true, true, 'tives'],
  23973. ['evom', 4, true, true, 'moves'],
  23974. ['ffats', 5, true, true, 'staves'],
  23975. ['ff', 2, true, true, 'ffs'],
  23976. ['f', 1, true, true, ['fs', 'ves']],
  23977. ['hc', 2, true, true, 'ches'],
  23978. ['hs', 2, true, true, 'shes'],
  23979. ['htoot', 5, true, true, 'teeth'],
  23980. ['mubla', 5, true, true, 'albums'],
  23981. ['mu', 2, true, true, 'a'],
  23982. ['nam', 3, true, true, 'men'],
  23983. ['nosrep', 6, true, true, ['persons', 'people']],
  23984. ['noiretirc', 9, true, true, 'criteria'],
  23985. ['nonemonehp', 10, true, true, 'phenomena'],
  23986. ['ohce', 4, true, true, 'echoes'],
  23987. ['oreh', 4, true, true, 'heroes'],
  23988. ['salta', 5, true, true, 'atlases'],
  23989. ['saila', 5, true, true, 'aliases'],
  23990. ['siri', 4, true, true, 'irises'],
  23991. ['sis', 3, true, true, 'ses'],
  23992. ['ss', 2, true, false, 'sses'],
  23993. ['suballys', 8, true, true, 'syllabi'],
  23994. ['sub', 3, true, true, 'buses'],
  23995. ['suc', 3, true, true, 'cuses'],
  23996. ['supmacoppih', 11, false, false, 'hippocampi'],
  23997. ['sup', 3, true, true, 'puses'],
  23998. ['sutats', 6, true, true, ['status', 'statuses']],
  23999. ['sutcep', 6, true, true, 'pectuses'],
  24000. ['su', 2, true, true, 'i'],
  24001. ['swen', 4, true, true, 'news'],
  24002. ['toof', 4, true, true, 'feet'],
  24003. ['uae', 3, false, true, ['eaus', 'eaux']],
  24004. ['xo', 2, false, false, 'oxen'],
  24005. ['xaoh', 4, true, false, 'hoaxes'],
  24006. ['xedni', 5, false, true, ['indicies', 'indexes']],
  24007. ['xaf', 3, true, true, ['faxes', 'faxxes']],
  24008. ['xo', 2, false, true, 'oxes'],
  24009. ['x', 1, true, false, ['ces', 'xes']],
  24010. ['y', 1, false, true, 'ies'],
  24011. ['ziuq', 4, true, false, 'quizzes'],
  24012. ['z', 1, true, true, 'zes'],
  24013. ];
  24014. private const UNINFLECTED = [
  24015. '',
  24016. 'atad',
  24017. 'reed',
  24018. 'tnempiuqe',
  24019. 'kcabdeef',
  24020. 'hsif',
  24021. 'htlaeh',
  24022. 'yrotsih',
  24023. 'ofni',
  24024. 'noitamrofni',
  24025. 'yenom',
  24026. 'esoom',
  24027. 'seires',
  24028. 'peehs',
  24029. 'seiceps',
  24030. 'ciffart',
  24031. 'tfarcria',
  24032. 'erawdrah',
  24033. ];
  24034. public function singularize(string $plural): array
  24035. {
  24036. $pluralRev = strrev($plural);
  24037. $lowerPluralRev = strtolower($pluralRev);
  24038. $pluralLength = \strlen($lowerPluralRev);
  24039. if (\in_array($lowerPluralRev, self::UNINFLECTED, true)) {
  24040. return [$plural];
  24041. }
  24042. foreach (self::PLURAL_MAP as $map) {
  24043. $suffix = $map[0];
  24044. $suffixLength = $map[1];
  24045. $j = 0;
  24046. while ($suffix[$j] === $lowerPluralRev[$j]) {
  24047. ++$j;
  24048. if ($j === $suffixLength) {
  24049. if ($j < $pluralLength) {
  24050. $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]);
  24051. if (!$map[2] && $nextIsVowel) {
  24052. break;
  24053. }
  24054. if (!$map[3] && !$nextIsVowel) {
  24055. break;
  24056. }
  24057. }
  24058. $newBase = substr($plural, 0, $pluralLength - $suffixLength);
  24059. $newSuffix = $map[4];
  24060. $firstUpper = ctype_upper($pluralRev[$j - 1]);
  24061. if (\is_array($newSuffix)) {
  24062. $singulars = [];
  24063. foreach ($newSuffix as $newSuffixEntry) {
  24064. $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
  24065. }
  24066. return $singulars;
  24067. }
  24068. return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];
  24069. }
  24070. if ($j === $pluralLength) {
  24071. break;
  24072. }
  24073. }
  24074. }
  24075. return [$plural];
  24076. }
  24077. public function pluralize(string $singular): array
  24078. {
  24079. $singularRev = strrev($singular);
  24080. $lowerSingularRev = strtolower($singularRev);
  24081. $singularLength = \strlen($lowerSingularRev);
  24082. if (\in_array($lowerSingularRev, self::UNINFLECTED, true)) {
  24083. return [$singular];
  24084. }
  24085. foreach (self::SINGULAR_MAP as $map) {
  24086. $suffix = $map[0];
  24087. $suffixLength = $map[1];
  24088. $j = 0;
  24089. while ($suffix[$j] === $lowerSingularRev[$j]) {
  24090. ++$j;
  24091. if ($j === $suffixLength) {
  24092. if ($j < $singularLength) {
  24093. $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]);
  24094. if (!$map[2] && $nextIsVowel) {
  24095. break;
  24096. }
  24097. if (!$map[3] && !$nextIsVowel) {
  24098. break;
  24099. }
  24100. }
  24101. $newBase = substr($singular, 0, $singularLength - $suffixLength);
  24102. $newSuffix = $map[4];
  24103. $firstUpper = ctype_upper($singularRev[$j - 1]);
  24104. if (\is_array($newSuffix)) {
  24105. $plurals = [];
  24106. foreach ($newSuffix as $newSuffixEntry) {
  24107. $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
  24108. }
  24109. return $plurals;
  24110. }
  24111. return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];
  24112. }
  24113. if ($j === $singularLength) {
  24114. break;
  24115. }
  24116. }
  24117. }
  24118. return [$singular.'s'];
  24119. }
  24120. }
  24121. <?php
  24122. namespace Symfony\Component\String;
  24123. use Symfony\Component\String\Exception\ExceptionInterface;
  24124. use Symfony\Component\String\Exception\InvalidArgumentException;
  24125. use Symfony\Component\String\Exception\RuntimeException;
  24126. abstract class AbstractUnicodeString extends AbstractString
  24127. {
  24128. public const NFC = \Normalizer::NFC;
  24129. public const NFD = \Normalizer::NFD;
  24130. public const NFKC = \Normalizer::NFKC;
  24131. public const NFKD = \Normalizer::NFKD;
  24132. private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
  24133. private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', '�', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', '�', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', '�', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', '�', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', '�', 'ᾎ', '�', '�', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', '�', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', '�', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ'];
  24134. private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', '�', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', '�', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', '�', 'ὒ', 'ὔ', 'ὖ', 'ἀι', '�ι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', '�ι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ'];
  24135. private const UPPER_FROM = ['ß', 'ff', '�', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'և', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ', 'ʼn', '�', 'ΰ', 'ǰ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', '�', 'ὒ', 'ὔ', 'ὖ', 'ᾶ', 'ῆ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'ῢ', 'ΰ', 'ῤ', 'ῦ', 'ῧ', 'ῶ'];
  24136. private const UPPER_TO = ['SS', 'FF', 'FI', 'FL', 'FFI', 'FFL', 'ST', 'ST', 'ԵՒ', 'ՄՆ', 'ՄԵ', 'ՄԻ', 'ՎՆ', 'ՄԽ', 'ʼN', 'Ϊ�', 'Ϋ�', 'J̌', 'H̱', 'T̈', 'W̊', 'Y̊', 'Aʾ', 'Υ̓', 'Υ̓̀', 'Υ̓�', 'Υ̓͂', 'Α͂', 'Η͂', 'Ϊ̀', 'Ϊ�', 'Ι͂', 'Ϊ͂', 'Ϋ̀', 'Ϋ�', 'Ρ̓', 'Υ͂', 'Ϋ͂', 'Ω͂'];
  24137. private const TRANSLIT_FROM = ['Æ', '�', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', '�', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', '�', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', '�', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', '�', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', '�', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', '�', 'Ɏ', '�', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', '�', '�', 'ʑ', 'ʙ', 'ʛ', 'ʜ', '�', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', '�', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', '�', '�', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', '�', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', '�', 'ᶎ', '�', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', '�', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '�', '�', '�', '�', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '�', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '�', '„', '‟', '′', '″', '�', '〞', '«', '»', '‹', '›', '�', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '�', '�', '�', '�', '�', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '�', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆'];
  24138. private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))'];
  24139. private static $transliterators = [];
  24140. private static $tableZero;
  24141. private static $tableWide;
  24142. public static function fromCodePoints(int ...$codes): self
  24143. {
  24144. $string = '';
  24145. foreach ($codes as $code) {
  24146. if (0x80 > $code %= 0x200000) {
  24147. $string .= \chr($code);
  24148. } elseif (0x800 > $code) {
  24149. $string .= \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
  24150. } elseif (0x10000 > $code) {
  24151. $string .= \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  24152. } else {
  24153. $string .= \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  24154. }
  24155. }
  24156. return new static($string);
  24157. }
  24158. public function ascii(array $rules = []): self
  24159. {
  24160. $str = clone $this;
  24161. $s = $str->string;
  24162. $str->string = '';
  24163. array_unshift($rules, 'nfd');
  24164. $rules[] = 'latin-ascii';
  24165. if (\function_exists('transliterator_transliterate')) {
  24166. $rules[] = 'any-latin/bgn';
  24167. }
  24168. $rules[] = 'nfkd';
  24169. $rules[] = '[:nonspacing mark:] remove';
  24170. while (\strlen($s) - 1 > $i = strspn($s, self::ASCII)) {
  24171. if (0 < --$i) {
  24172. $str->string .= substr($s, 0, $i);
  24173. $s = substr($s, $i);
  24174. }
  24175. if (!$rule = array_shift($rules)) {
  24176. $rules = [];
  24177. }
  24178. if ($rule instanceof \Transliterator) {
  24179. $s = $rule->transliterate($s);
  24180. } elseif ($rule instanceof \Closure) {
  24181. $s = $rule($s);
  24182. } elseif ($rule) {
  24183. if ('nfd' === $rule = strtolower($rule)) {
  24184. normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD);
  24185. } elseif ('nfkd' === $rule) {
  24186. normalizer_is_normalized($s, self::NFKD) ?: $s = normalizer_normalize($s, self::NFKD);
  24187. } elseif ('[:nonspacing mark:] remove' === $rule) {
  24188. $s = preg_replace('/\p{Mn}++/u', '', $s);
  24189. } elseif ('latin-ascii' === $rule) {
  24190. $s = str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s);
  24191. } elseif ('de-ascii' === $rule) {
  24192. $s = preg_replace("/([AUO])\u{0308}(?=\p{Ll})/u", '$1e', $s);
  24193. $s = str_replace(["a\u{0308}", "o\u{0308}", "u\u{0308}", "A\u{0308}", "O\u{0308}", "U\u{0308}"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s);
  24194. } elseif (\function_exists('transliterator_transliterate')) {
  24195. if (null === $transliterator = self::$transliterators[$rule] ?? self::$transliterators[$rule] = \Transliterator::create($rule)) {
  24196. if ('any-latin/bgn' === $rule) {
  24197. $rule = 'any-latin';
  24198. $transliterator = self::$transliterators[$rule] ?? self::$transliterators[$rule] = \Transliterator::create($rule);
  24199. }
  24200. if (null === $transliterator) {
  24201. throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule));
  24202. }
  24203. self::$transliterators['any-latin/bgn'] = $transliterator;
  24204. }
  24205. $s = $transliterator->transliterate($s);
  24206. }
  24207. } elseif (!\function_exists('iconv')) {
  24208. $s = preg_replace('/[^\x00-\x7F]/u', '?', $s);
  24209. } else {
  24210. $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) {
  24211. $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]);
  24212. if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) {
  24213. throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class));
  24214. }
  24215. return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?');
  24216. }, $s);
  24217. }
  24218. }
  24219. $str->string .= $s;
  24220. return $str;
  24221. }
  24222. public function camel(): parent
  24223. {
  24224. $str = clone $this;
  24225. $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?!\p{Lu})/u', static function ($m) use (&$i) {
  24226. return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
  24227. }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string)));
  24228. return $str;
  24229. }
  24230. public function codePointsAt(int $offset): array
  24231. {
  24232. $str = $this->slice($offset, 1);
  24233. if ('' === $str->string) {
  24234. return [];
  24235. }
  24236. $codePoints = [];
  24237. foreach (preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
  24238. $codePoints[] = mb_ord($c, 'UTF-8');
  24239. }
  24240. return $codePoints;
  24241. }
  24242. public function folded(bool $compat = true): parent
  24243. {
  24244. $str = clone $this;
  24245. if (!$compat || \PHP_VERSION_ID < 70300 || !\defined('Normalizer::NFKC_CF')) {
  24246. $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC);
  24247. $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8');
  24248. } else {
  24249. $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF);
  24250. }
  24251. return $str;
  24252. }
  24253. public function join(array $strings, ?string $lastGlue = null): parent
  24254. {
  24255. $str = clone $this;
  24256. $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : '';
  24257. $str->string = implode($this->string, $strings).$tail;
  24258. if (!preg_match('//u', $str->string)) {
  24259. throw new InvalidArgumentException('Invalid UTF-8 string.');
  24260. }
  24261. return $str;
  24262. }
  24263. public function lower(): parent
  24264. {
  24265. $str = clone $this;
  24266. $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8');
  24267. return $str;
  24268. }
  24269. public function match(string $regexp, int $flags = 0, int $offset = 0): array
  24270. {
  24271. $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';
  24272. if ($this->ignoreCase) {
  24273. $regexp .= 'i';
  24274. }
  24275. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  24276. try {
  24277. if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
  24278. $lastError = preg_last_error();
  24279. foreach (get_defined_constants(true)['pcre'] as $k => $v) {
  24280. if ($lastError === $v && '_ERROR' === substr($k, -6)) {
  24281. throw new RuntimeException('Matching failed with '.$k.'.');
  24282. }
  24283. }
  24284. throw new RuntimeException('Matching failed with unknown error code.');
  24285. }
  24286. } finally {
  24287. restore_error_handler();
  24288. }
  24289. return $matches;
  24290. }
  24291. public function normalize(int $form = self::NFC): self
  24292. {
  24293. if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) {
  24294. throw new InvalidArgumentException('Unsupported normalization form.');
  24295. }
  24296. $str = clone $this;
  24297. normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);
  24298. return $str;
  24299. }
  24300. public function padBoth(int $length, string $padStr = ' '): parent
  24301. {
  24302. if ('' === $padStr || !preg_match('//u', $padStr)) {
  24303. throw new InvalidArgumentException('Invalid UTF-8 string.');
  24304. }
  24305. $pad = clone $this;
  24306. $pad->string = $padStr;
  24307. return $this->pad($length, $pad, \STR_PAD_BOTH);
  24308. }
  24309. public function padEnd(int $length, string $padStr = ' '): parent
  24310. {
  24311. if ('' === $padStr || !preg_match('//u', $padStr)) {
  24312. throw new InvalidArgumentException('Invalid UTF-8 string.');
  24313. }
  24314. $pad = clone $this;
  24315. $pad->string = $padStr;
  24316. return $this->pad($length, $pad, \STR_PAD_RIGHT);
  24317. }
  24318. public function padStart(int $length, string $padStr = ' '): parent
  24319. {
  24320. if ('' === $padStr || !preg_match('//u', $padStr)) {
  24321. throw new InvalidArgumentException('Invalid UTF-8 string.');
  24322. }
  24323. $pad = clone $this;
  24324. $pad->string = $padStr;
  24325. return $this->pad($length, $pad, \STR_PAD_LEFT);
  24326. }
  24327. public function replaceMatches(string $fromRegexp, $to): parent
  24328. {
  24329. if ($this->ignoreCase) {
  24330. $fromRegexp .= 'i';
  24331. }
  24332. if (\is_array($to) || $to instanceof \Closure) {
  24333. if (!\is_callable($to)) {
  24334. throw new \TypeError(sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
  24335. }
  24336. $replace = 'preg_replace_callback';
  24337. $to = static function (array $m) use ($to): string {
  24338. $to = $to($m);
  24339. if ('' !== $to && (!\is_string($to) || !preg_match('//u', $to))) {
  24340. throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.');
  24341. }
  24342. return $to;
  24343. };
  24344. } elseif ('' !== $to && !preg_match('//u', $to)) {
  24345. throw new InvalidArgumentException('Invalid UTF-8 string.');
  24346. } else {
  24347. $replace = 'preg_replace';
  24348. }
  24349. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  24350. try {
  24351. if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) {
  24352. $lastError = preg_last_error();
  24353. foreach (get_defined_constants(true)['pcre'] as $k => $v) {
  24354. if ($lastError === $v && '_ERROR' === substr($k, -6)) {
  24355. throw new RuntimeException('Matching failed with '.$k.'.');
  24356. }
  24357. }
  24358. throw new RuntimeException('Matching failed with unknown error code.');
  24359. }
  24360. } finally {
  24361. restore_error_handler();
  24362. }
  24363. $str = clone $this;
  24364. $str->string = $string;
  24365. return $str;
  24366. }
  24367. public function reverse(): parent
  24368. {
  24369. $str = clone $this;
  24370. $str->string = implode('', array_reverse(preg_split('/(\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY)));
  24371. return $str;
  24372. }
  24373. public function snake(): parent
  24374. {
  24375. $str = $this->camel();
  24376. $str->string = mb_strtolower(preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1_\2', $str->string), 'UTF-8');
  24377. return $str;
  24378. }
  24379. public function title(bool $allWords = false): parent
  24380. {
  24381. $str = clone $this;
  24382. $limit = $allWords ? -1 : 1;
  24383. $str->string = preg_replace_callback('/\b./u', static function (array $m): string {
  24384. return mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
  24385. }, $str->string, $limit);
  24386. return $str;
  24387. }
  24388. public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
  24389. {
  24390. if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
  24391. throw new InvalidArgumentException('Invalid UTF-8 chars.');
  24392. }
  24393. $chars = preg_quote($chars);
  24394. $str = clone $this;
  24395. $str->string = preg_replace("{^[$chars]++|[$chars]++$}uD", '', $str->string);
  24396. return $str;
  24397. }
  24398. public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
  24399. {
  24400. if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
  24401. throw new InvalidArgumentException('Invalid UTF-8 chars.');
  24402. }
  24403. $chars = preg_quote($chars);
  24404. $str = clone $this;
  24405. $str->string = preg_replace("{[$chars]++$}uD", '', $str->string);
  24406. return $str;
  24407. }
  24408. public function trimPrefix($prefix): parent
  24409. {
  24410. if (!$this->ignoreCase) {
  24411. return parent::trimPrefix($prefix);
  24412. }
  24413. $str = clone $this;
  24414. if ($prefix instanceof \Traversable) {
  24415. $prefix = iterator_to_array($prefix, false);
  24416. } elseif ($prefix instanceof parent) {
  24417. $prefix = $prefix->string;
  24418. }
  24419. $prefix = implode('|', array_map('preg_quote', (array) $prefix));
  24420. $str->string = preg_replace("{^(?:$prefix)}iuD", '', $this->string);
  24421. return $str;
  24422. }
  24423. public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
  24424. {
  24425. if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
  24426. throw new InvalidArgumentException('Invalid UTF-8 chars.');
  24427. }
  24428. $chars = preg_quote($chars);
  24429. $str = clone $this;
  24430. $str->string = preg_replace("{^[$chars]++}uD", '', $str->string);
  24431. return $str;
  24432. }
  24433. public function trimSuffix($suffix): parent
  24434. {
  24435. if (!$this->ignoreCase) {
  24436. return parent::trimSuffix($suffix);
  24437. }
  24438. $str = clone $this;
  24439. if ($suffix instanceof \Traversable) {
  24440. $suffix = iterator_to_array($suffix, false);
  24441. } elseif ($suffix instanceof parent) {
  24442. $suffix = $suffix->string;
  24443. }
  24444. $suffix = implode('|', array_map('preg_quote', (array) $suffix));
  24445. $str->string = preg_replace("{(?:$suffix)$}iuD", '', $this->string);
  24446. return $str;
  24447. }
  24448. public function upper(): parent
  24449. {
  24450. $str = clone $this;
  24451. $str->string = mb_strtoupper($str->string, 'UTF-8');
  24452. if (\PHP_VERSION_ID < 70300) {
  24453. $str->string = str_replace(self::UPPER_FROM, self::UPPER_TO, $str->string);
  24454. }
  24455. return $str;
  24456. }
  24457. public function width(bool $ignoreAnsiDecoration = true): int
  24458. {
  24459. $width = 0;
  24460. $s = str_replace(["\x00", "\x05", "\x07"], '', $this->string);
  24461. if (false !== strpos($s, "\r")) {
  24462. $s = str_replace(["\r\n", "\r"], "\n", $s);
  24463. }
  24464. if (!$ignoreAnsiDecoration) {
  24465. $s = preg_replace('/[\p{Cc}\x7F]++/u', '', $s);
  24466. }
  24467. foreach (explode("\n", $s) as $s) {
  24468. if ($ignoreAnsiDecoration) {
  24469. $s = preg_replace('/(?:\x1B(?:
  24470. \[ [\x30-\x3F]*+ [\x20-\x2F]*+ [\x40-\x7E]
  24471. | [P\]X^_] .*? \x1B\\\\
  24472. | [\x41-\x7E]
  24473. )|[\p{Cc}\x7F]++)/xu', '', $s);
  24474. }
  24475. $lineWidth = $this->wcswidth($s);
  24476. if ($lineWidth > $width) {
  24477. $width = $lineWidth;
  24478. }
  24479. }
  24480. return $width;
  24481. }
  24482. private function pad(int $len, self $pad, int $type): parent
  24483. {
  24484. $sLen = $this->length();
  24485. if ($len <= $sLen) {
  24486. return clone $this;
  24487. }
  24488. $padLen = $pad->length();
  24489. $freeLen = $len - $sLen;
  24490. $len = $freeLen % $padLen;
  24491. switch ($type) {
  24492. case \STR_PAD_RIGHT:
  24493. return $this->append(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
  24494. case \STR_PAD_LEFT:
  24495. return $this->prepend(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
  24496. case \STR_PAD_BOTH:
  24497. $freeLen /= 2;
  24498. $rightLen = ceil($freeLen);
  24499. $len = $rightLen % $padLen;
  24500. $str = $this->append(str_repeat($pad->string, intdiv($rightLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
  24501. $leftLen = floor($freeLen);
  24502. $len = $leftLen % $padLen;
  24503. return $str->prepend(str_repeat($pad->string, intdiv($leftLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
  24504. default:
  24505. throw new InvalidArgumentException('Invalid padding type.');
  24506. }
  24507. }
  24508. private function wcswidth(string $string): int
  24509. {
  24510. $width = 0;
  24511. foreach (preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
  24512. $codePoint = mb_ord($c, 'UTF-8');
  24513. if (0 === $codePoint
  24514. || 0x034F === $codePoint
  24515. || (0x200B <= $codePoint && 0x200F >= $codePoint)
  24516. || 0x2028 === $codePoint
  24517. || 0x2029 === $codePoint
  24518. || (0x202A <= $codePoint && 0x202E >= $codePoint)
  24519. || (0x2060 <= $codePoint && 0x2063 >= $codePoint)
  24520. ) {
  24521. continue;
  24522. }
  24523. if (32 > $codePoint
  24524. || (0x07F <= $codePoint && 0x0A0 > $codePoint)
  24525. ) {
  24526. return -1;
  24527. }
  24528. if (null === self::$tableZero) {
  24529. self::$tableZero = require __DIR__.'/Resources/data/wcswidth_table_zero.php';
  24530. }
  24531. if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) {
  24532. $lbound = 0;
  24533. while ($ubound >= $lbound) {
  24534. $mid = floor(($lbound + $ubound) / 2);
  24535. if ($codePoint > self::$tableZero[$mid][1]) {
  24536. $lbound = $mid + 1;
  24537. } elseif ($codePoint < self::$tableZero[$mid][0]) {
  24538. $ubound = $mid - 1;
  24539. } else {
  24540. continue 2;
  24541. }
  24542. }
  24543. }
  24544. if (null === self::$tableWide) {
  24545. self::$tableWide = require __DIR__.'/Resources/data/wcswidth_table_wide.php';
  24546. }
  24547. if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) {
  24548. $lbound = 0;
  24549. while ($ubound >= $lbound) {
  24550. $mid = floor(($lbound + $ubound) / 2);
  24551. if ($codePoint > self::$tableWide[$mid][1]) {
  24552. $lbound = $mid + 1;
  24553. } elseif ($codePoint < self::$tableWide[$mid][0]) {
  24554. $ubound = $mid - 1;
  24555. } else {
  24556. $width += 2;
  24557. continue 2;
  24558. }
  24559. }
  24560. }
  24561. ++$width;
  24562. }
  24563. return $width;
  24564. }
  24565. }
  24566. <?php
  24567. namespace Symfony\Component\String;
  24568. class LazyString implements \Stringable, \JsonSerializable
  24569. {
  24570. private $value;
  24571. public static function fromCallable($callback, ...$arguments): self
  24572. {
  24573. if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) {
  24574. throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, get_debug_type($callback)));
  24575. }
  24576. $lazyString = new static();
  24577. $lazyString->value = static function () use (&$callback, &$arguments, &$value): string {
  24578. if (null !== $arguments) {
  24579. if (!\is_callable($callback)) {
  24580. $callback[0] = $callback[0]();
  24581. $callback[1] = $callback[1] ?? '__invoke';
  24582. }
  24583. $value = $callback(...$arguments);
  24584. $callback = self::getPrettyName($callback);
  24585. $arguments = null;
  24586. }
  24587. return $value ?? '';
  24588. };
  24589. return $lazyString;
  24590. }
  24591. public static function fromStringable($value): self
  24592. {
  24593. if (!self::isStringable($value)) {
  24594. throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a scalar or a stringable object, "%s" given.', __METHOD__, get_debug_type($value)));
  24595. }
  24596. if (\is_object($value)) {
  24597. return static::fromCallable([$value, '__toString']);
  24598. }
  24599. $lazyString = new static();
  24600. $lazyString->value = (string) $value;
  24601. return $lazyString;
  24602. }
  24603. final public static function isStringable($value): bool
  24604. {
  24605. return \is_string($value) || $value instanceof self || (\is_object($value) ? method_exists($value, '__toString') : \is_scalar($value));
  24606. }
  24607. final public static function resolve($value): string
  24608. {
  24609. return $value;
  24610. }
  24611. public function __toString()
  24612. {
  24613. if (\is_string($this->value)) {
  24614. return $this->value;
  24615. }
  24616. try {
  24617. return $this->value = ($this->value)();
  24618. } catch (\Throwable $e) {
  24619. if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) {
  24620. $type = explode(', ', $e->getMessage());
  24621. $type = substr(array_pop($type), 0, -\strlen(' returned'));
  24622. $r = new \ReflectionFunction($this->value);
  24623. $callback = $r->getStaticVariables()['callback'];
  24624. $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type));
  24625. }
  24626. if (\PHP_VERSION_ID < 70400) {
  24627. return trigger_error($e, \E_USER_ERROR);
  24628. }
  24629. throw $e;
  24630. }
  24631. }
  24632. public function __sleep(): array
  24633. {
  24634. $this->__toString();
  24635. return ['value'];
  24636. }
  24637. public function jsonSerialize(): string
  24638. {
  24639. return $this->__toString();
  24640. }
  24641. private function __construct()
  24642. {
  24643. }
  24644. private static function getPrettyName(callable $callback): string
  24645. {
  24646. if (\is_string($callback)) {
  24647. return $callback;
  24648. }
  24649. if (\is_array($callback)) {
  24650. $class = \is_object($callback[0]) ? get_debug_type($callback[0]) : $callback[0];
  24651. $method = $callback[1];
  24652. } elseif ($callback instanceof \Closure) {
  24653. $r = new \ReflectionFunction($callback);
  24654. if (str_contains($r->name, '{closure') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
  24655. return $r->name;
  24656. }
  24657. $class = $class->name;
  24658. $method = $r->name;
  24659. } else {
  24660. $class = get_debug_type($callback);
  24661. $method = '__invoke';
  24662. }
  24663. return $class.'::'.$method;
  24664. }
  24665. }
  24666. <?php
  24667. namespace Symfony\Component\String;
  24668. use Symfony\Component\String\Exception\ExceptionInterface;
  24669. use Symfony\Component\String\Exception\InvalidArgumentException;
  24670. use Symfony\Component\String\Exception\RuntimeException;
  24671. class ByteString extends AbstractString
  24672. {
  24673. private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
  24674. public function __construct(string $string = '')
  24675. {
  24676. $this->string = $string;
  24677. }
  24678. public static function fromRandom(int $length = 16, ?string $alphabet = null): self
  24679. {
  24680. if ($length <= 0) {
  24681. throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length));
  24682. }
  24683. $alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC;
  24684. $alphabetSize = \strlen($alphabet);
  24685. $bits = (int) ceil(log($alphabetSize, 2.0));
  24686. if ($bits <= 0 || $bits > 56) {
  24687. throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.');
  24688. }
  24689. $ret = '';
  24690. while ($length > 0) {
  24691. $urandomLength = (int) ceil(2 * $length * $bits / 8.0);
  24692. $data = random_bytes($urandomLength);
  24693. $unpackedData = 0;
  24694. $unpackedBits = 0;
  24695. for ($i = 0; $i < $urandomLength && $length > 0; ++$i) {
  24696. $unpackedData = ($unpackedData << 8) | \ord($data[$i]);
  24697. $unpackedBits += 8;
  24698. for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) {
  24699. $index = ($unpackedData & ((1 << $bits) - 1));
  24700. $unpackedData >>= $bits;
  24701. if ($index < $alphabetSize) {
  24702. $ret .= $alphabet[$index];
  24703. --$length;
  24704. }
  24705. }
  24706. }
  24707. }
  24708. return new static($ret);
  24709. }
  24710. public function bytesAt(int $offset): array
  24711. {
  24712. $str = $this->string[$offset] ?? '';
  24713. return '' === $str ? [] : [\ord($str)];
  24714. }
  24715. public function append(string ...$suffix): parent
  24716. {
  24717. $str = clone $this;
  24718. $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);
  24719. return $str;
  24720. }
  24721. public function camel(): parent
  24722. {
  24723. $str = clone $this;
  24724. $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string))));
  24725. $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]);
  24726. $str->string = implode('', $parts);
  24727. return $str;
  24728. }
  24729. public function chunk(int $length = 1): array
  24730. {
  24731. if (1 > $length) {
  24732. throw new InvalidArgumentException('The chunk length must be greater than zero.');
  24733. }
  24734. if ('' === $this->string) {
  24735. return [];
  24736. }
  24737. $str = clone $this;
  24738. $chunks = [];
  24739. foreach (str_split($this->string, $length) as $chunk) {
  24740. $str->string = $chunk;
  24741. $chunks[] = clone $str;
  24742. }
  24743. return $chunks;
  24744. }
  24745. public function endsWith($suffix): bool
  24746. {
  24747. if ($suffix instanceof parent) {
  24748. $suffix = $suffix->string;
  24749. } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
  24750. return parent::endsWith($suffix);
  24751. } else {
  24752. $suffix = (string) $suffix;
  24753. }
  24754. return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase);
  24755. }
  24756. public function equalsTo($string): bool
  24757. {
  24758. if ($string instanceof parent) {
  24759. $string = $string->string;
  24760. } elseif (\is_array($string) || $string instanceof \Traversable) {
  24761. return parent::equalsTo($string);
  24762. } else {
  24763. $string = (string) $string;
  24764. }
  24765. if ('' !== $string && $this->ignoreCase) {
  24766. return 0 === strcasecmp($string, $this->string);
  24767. }
  24768. return $string === $this->string;
  24769. }
  24770. public function folded(): parent
  24771. {
  24772. $str = clone $this;
  24773. $str->string = strtolower($str->string);
  24774. return $str;
  24775. }
  24776. public function indexOf($needle, int $offset = 0): ?int
  24777. {
  24778. if ($needle instanceof parent) {
  24779. $needle = $needle->string;
  24780. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  24781. return parent::indexOf($needle, $offset);
  24782. } else {
  24783. $needle = (string) $needle;
  24784. }
  24785. if ('' === $needle) {
  24786. return null;
  24787. }
  24788. $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset);
  24789. return false === $i ? null : $i;
  24790. }
  24791. public function indexOfLast($needle, int $offset = 0): ?int
  24792. {
  24793. if ($needle instanceof parent) {
  24794. $needle = $needle->string;
  24795. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  24796. return parent::indexOfLast($needle, $offset);
  24797. } else {
  24798. $needle = (string) $needle;
  24799. }
  24800. if ('' === $needle) {
  24801. return null;
  24802. }
  24803. $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset);
  24804. return false === $i ? null : $i;
  24805. }
  24806. public function isUtf8(): bool
  24807. {
  24808. return '' === $this->string || preg_match('//u', $this->string);
  24809. }
  24810. public function join(array $strings, ?string $lastGlue = null): parent
  24811. {
  24812. $str = clone $this;
  24813. $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : '';
  24814. $str->string = implode($this->string, $strings).$tail;
  24815. return $str;
  24816. }
  24817. public function length(): int
  24818. {
  24819. return \strlen($this->string);
  24820. }
  24821. public function lower(): parent
  24822. {
  24823. $str = clone $this;
  24824. $str->string = strtolower($str->string);
  24825. return $str;
  24826. }
  24827. public function match(string $regexp, int $flags = 0, int $offset = 0): array
  24828. {
  24829. $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';
  24830. if ($this->ignoreCase) {
  24831. $regexp .= 'i';
  24832. }
  24833. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  24834. try {
  24835. if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
  24836. $lastError = preg_last_error();
  24837. foreach (get_defined_constants(true)['pcre'] as $k => $v) {
  24838. if ($lastError === $v && '_ERROR' === substr($k, -6)) {
  24839. throw new RuntimeException('Matching failed with '.$k.'.');
  24840. }
  24841. }
  24842. throw new RuntimeException('Matching failed with unknown error code.');
  24843. }
  24844. } finally {
  24845. restore_error_handler();
  24846. }
  24847. return $matches;
  24848. }
  24849. public function padBoth(int $length, string $padStr = ' '): parent
  24850. {
  24851. $str = clone $this;
  24852. $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH);
  24853. return $str;
  24854. }
  24855. public function padEnd(int $length, string $padStr = ' '): parent
  24856. {
  24857. $str = clone $this;
  24858. $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT);
  24859. return $str;
  24860. }
  24861. public function padStart(int $length, string $padStr = ' '): parent
  24862. {
  24863. $str = clone $this;
  24864. $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT);
  24865. return $str;
  24866. }
  24867. public function prepend(string ...$prefix): parent
  24868. {
  24869. $str = clone $this;
  24870. $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string;
  24871. return $str;
  24872. }
  24873. public function replace(string $from, string $to): parent
  24874. {
  24875. $str = clone $this;
  24876. if ('' !== $from) {
  24877. $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string);
  24878. }
  24879. return $str;
  24880. }
  24881. public function replaceMatches(string $fromRegexp, $to): parent
  24882. {
  24883. if ($this->ignoreCase) {
  24884. $fromRegexp .= 'i';
  24885. }
  24886. if (\is_array($to)) {
  24887. if (!\is_callable($to)) {
  24888. throw new \TypeError(sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
  24889. }
  24890. $replace = 'preg_replace_callback';
  24891. } else {
  24892. $replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace';
  24893. }
  24894. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  24895. try {
  24896. if (null === $string = $replace($fromRegexp, $to, $this->string)) {
  24897. $lastError = preg_last_error();
  24898. foreach (get_defined_constants(true)['pcre'] as $k => $v) {
  24899. if ($lastError === $v && '_ERROR' === substr($k, -6)) {
  24900. throw new RuntimeException('Matching failed with '.$k.'.');
  24901. }
  24902. }
  24903. throw new RuntimeException('Matching failed with unknown error code.');
  24904. }
  24905. } finally {
  24906. restore_error_handler();
  24907. }
  24908. $str = clone $this;
  24909. $str->string = $string;
  24910. return $str;
  24911. }
  24912. public function reverse(): parent
  24913. {
  24914. $str = clone $this;
  24915. $str->string = strrev($str->string);
  24916. return $str;
  24917. }
  24918. public function slice(int $start = 0, ?int $length = null): parent
  24919. {
  24920. $str = clone $this;
  24921. $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX);
  24922. return $str;
  24923. }
  24924. public function snake(): parent
  24925. {
  24926. $str = $this->camel();
  24927. $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string));
  24928. return $str;
  24929. }
  24930. public function splice(string $replacement, int $start = 0, ?int $length = null): parent
  24931. {
  24932. $str = clone $this;
  24933. $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
  24934. return $str;
  24935. }
  24936. public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
  24937. {
  24938. if (1 > $limit = $limit ?? \PHP_INT_MAX) {
  24939. throw new InvalidArgumentException('Split limit must be a positive integer.');
  24940. }
  24941. if ('' === $delimiter) {
  24942. throw new InvalidArgumentException('Split delimiter is empty.');
  24943. }
  24944. if (null !== $flags) {
  24945. return parent::split($delimiter, $limit, $flags);
  24946. }
  24947. $str = clone $this;
  24948. $chunks = $this->ignoreCase
  24949. ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit)
  24950. : explode($delimiter, $this->string, $limit);
  24951. foreach ($chunks as &$chunk) {
  24952. $str->string = $chunk;
  24953. $chunk = clone $str;
  24954. }
  24955. return $chunks;
  24956. }
  24957. public function startsWith($prefix): bool
  24958. {
  24959. if ($prefix instanceof parent) {
  24960. $prefix = $prefix->string;
  24961. } elseif (!\is_string($prefix)) {
  24962. return parent::startsWith($prefix);
  24963. }
  24964. return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \strlen($prefix)) : strncmp($this->string, $prefix, \strlen($prefix)));
  24965. }
  24966. public function title(bool $allWords = false): parent
  24967. {
  24968. $str = clone $this;
  24969. $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string);
  24970. return $str;
  24971. }
  24972. public function toUnicodeString(?string $fromEncoding = null): UnicodeString
  24973. {
  24974. return new UnicodeString($this->toCodePointString($fromEncoding)->string);
  24975. }
  24976. public function toCodePointString(?string $fromEncoding = null): CodePointString
  24977. {
  24978. $u = new CodePointString();
  24979. if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) {
  24980. $u->string = $this->string;
  24981. return $u;
  24982. }
  24983. set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
  24984. try {
  24985. try {
  24986. $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true);
  24987. } catch (InvalidArgumentException $e) {
  24988. if (!\function_exists('iconv')) {
  24989. throw $e;
  24990. }
  24991. $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string);
  24992. return $u;
  24993. }
  24994. } finally {
  24995. restore_error_handler();
  24996. }
  24997. if (!$validEncoding) {
  24998. throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252'));
  24999. }
  25000. $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252');
  25001. return $u;
  25002. }
  25003. public function trim(string $chars = " \t\n\r\0\x0B\x0C"): parent
  25004. {
  25005. $str = clone $this;
  25006. $str->string = trim($str->string, $chars);
  25007. return $str;
  25008. }
  25009. public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): parent
  25010. {
  25011. $str = clone $this;
  25012. $str->string = rtrim($str->string, $chars);
  25013. return $str;
  25014. }
  25015. public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): parent
  25016. {
  25017. $str = clone $this;
  25018. $str->string = ltrim($str->string, $chars);
  25019. return $str;
  25020. }
  25021. public function upper(): parent
  25022. {
  25023. $str = clone $this;
  25024. $str->string = strtoupper($str->string);
  25025. return $str;
  25026. }
  25027. public function width(bool $ignoreAnsiDecoration = true): int
  25028. {
  25029. $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\x80-\xFF]/', '?', $this->string);
  25030. return (new CodePointString($string))->width($ignoreAnsiDecoration);
  25031. }
  25032. }
  25033. <?php
  25034. namespace Symfony\Component\String;
  25035. use Symfony\Component\String\Exception\ExceptionInterface;
  25036. use Symfony\Component\String\Exception\InvalidArgumentException;
  25037. class UnicodeString extends AbstractUnicodeString
  25038. {
  25039. public function __construct(string $string = '')
  25040. {
  25041. $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string);
  25042. if (false === $this->string) {
  25043. throw new InvalidArgumentException('Invalid UTF-8 string.');
  25044. }
  25045. }
  25046. public function append(string ...$suffix): AbstractString
  25047. {
  25048. $str = clone $this;
  25049. $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix));
  25050. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25051. if (false === $str->string) {
  25052. throw new InvalidArgumentException('Invalid UTF-8 string.');
  25053. }
  25054. return $str;
  25055. }
  25056. public function chunk(int $length = 1): array
  25057. {
  25058. if (1 > $length) {
  25059. throw new InvalidArgumentException('The chunk length must be greater than zero.');
  25060. }
  25061. if ('' === $this->string) {
  25062. return [];
  25063. }
  25064. $rx = '/(';
  25065. while (65535 < $length) {
  25066. $rx .= '\X{65535}';
  25067. $length -= 65535;
  25068. }
  25069. $rx .= '\X{'.$length.'})/u';
  25070. $str = clone $this;
  25071. $chunks = [];
  25072. foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
  25073. $str->string = $chunk;
  25074. $chunks[] = clone $str;
  25075. }
  25076. return $chunks;
  25077. }
  25078. public function endsWith($suffix): bool
  25079. {
  25080. if ($suffix instanceof AbstractString) {
  25081. $suffix = $suffix->string;
  25082. } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
  25083. return parent::endsWith($suffix);
  25084. } else {
  25085. $suffix = (string) $suffix;
  25086. }
  25087. $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
  25088. normalizer_is_normalized($suffix, $form) ?: $suffix = normalizer_normalize($suffix, $form);
  25089. if ('' === $suffix || false === $suffix) {
  25090. return false;
  25091. }
  25092. if ($this->ignoreCase) {
  25093. return 0 === mb_stripos(grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8');
  25094. }
  25095. return $suffix === grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix));
  25096. }
  25097. public function equalsTo($string): bool
  25098. {
  25099. if ($string instanceof AbstractString) {
  25100. $string = $string->string;
  25101. } elseif (\is_array($string) || $string instanceof \Traversable) {
  25102. return parent::equalsTo($string);
  25103. } else {
  25104. $string = (string) $string;
  25105. }
  25106. $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
  25107. normalizer_is_normalized($string, $form) ?: $string = normalizer_normalize($string, $form);
  25108. if ('' !== $string && false !== $string && $this->ignoreCase) {
  25109. return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');
  25110. }
  25111. return $string === $this->string;
  25112. }
  25113. public function indexOf($needle, int $offset = 0): ?int
  25114. {
  25115. if ($needle instanceof AbstractString) {
  25116. $needle = $needle->string;
  25117. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  25118. return parent::indexOf($needle, $offset);
  25119. } else {
  25120. $needle = (string) $needle;
  25121. }
  25122. $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
  25123. normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);
  25124. if ('' === $needle || false === $needle) {
  25125. return null;
  25126. }
  25127. try {
  25128. $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset);
  25129. } catch (\ValueError $e) {
  25130. return null;
  25131. }
  25132. return false === $i ? null : $i;
  25133. }
  25134. public function indexOfLast($needle, int $offset = 0): ?int
  25135. {
  25136. if ($needle instanceof AbstractString) {
  25137. $needle = $needle->string;
  25138. } elseif (\is_array($needle) || $needle instanceof \Traversable) {
  25139. return parent::indexOfLast($needle, $offset);
  25140. } else {
  25141. $needle = (string) $needle;
  25142. }
  25143. $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
  25144. normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);
  25145. if ('' === $needle || false === $needle) {
  25146. return null;
  25147. }
  25148. $string = $this->string;
  25149. if (0 > $offset) {
  25150. if (0 > $offset += grapheme_strlen($needle)) {
  25151. $string = grapheme_substr($string, 0, $offset);
  25152. }
  25153. $offset = 0;
  25154. }
  25155. $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset);
  25156. return false === $i ? null : $i;
  25157. }
  25158. public function join(array $strings, ?string $lastGlue = null): AbstractString
  25159. {
  25160. $str = parent::join($strings, $lastGlue);
  25161. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25162. return $str;
  25163. }
  25164. public function length(): int
  25165. {
  25166. return grapheme_strlen($this->string);
  25167. }
  25168. public function normalize(int $form = self::NFC): parent
  25169. {
  25170. $str = clone $this;
  25171. if (\in_array($form, [self::NFC, self::NFKC], true)) {
  25172. normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);
  25173. } elseif (!\in_array($form, [self::NFD, self::NFKD], true)) {
  25174. throw new InvalidArgumentException('Unsupported normalization form.');
  25175. } elseif (!normalizer_is_normalized($str->string, $form)) {
  25176. $str->string = normalizer_normalize($str->string, $form);
  25177. $str->ignoreCase = null;
  25178. }
  25179. return $str;
  25180. }
  25181. public function prepend(string ...$prefix): AbstractString
  25182. {
  25183. $str = clone $this;
  25184. $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;
  25185. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25186. if (false === $str->string) {
  25187. throw new InvalidArgumentException('Invalid UTF-8 string.');
  25188. }
  25189. return $str;
  25190. }
  25191. public function replace(string $from, string $to): AbstractString
  25192. {
  25193. $str = clone $this;
  25194. normalizer_is_normalized($from) ?: $from = normalizer_normalize($from);
  25195. if ('' !== $from && false !== $from) {
  25196. $tail = $str->string;
  25197. $result = '';
  25198. $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
  25199. while ('' !== $tail && false !== $i = $indexOf($tail, $from)) {
  25200. $slice = grapheme_substr($tail, 0, $i);
  25201. $result .= $slice.$to;
  25202. $tail = substr($tail, \strlen($slice) + \strlen($from));
  25203. }
  25204. $str->string = $result.$tail;
  25205. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25206. if (false === $str->string) {
  25207. throw new InvalidArgumentException('Invalid UTF-8 string.');
  25208. }
  25209. }
  25210. return $str;
  25211. }
  25212. public function replaceMatches(string $fromRegexp, $to): AbstractString
  25213. {
  25214. $str = parent::replaceMatches($fromRegexp, $to);
  25215. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25216. return $str;
  25217. }
  25218. public function slice(int $start = 0, ?int $length = null): AbstractString
  25219. {
  25220. $str = clone $this;
  25221. if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
  25222. $start = 0;
  25223. }
  25224. $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647);
  25225. return $str;
  25226. }
  25227. public function splice(string $replacement, int $start = 0, ?int $length = null): AbstractString
  25228. {
  25229. $str = clone $this;
  25230. if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
  25231. $start = 0;
  25232. }
  25233. $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0;
  25234. $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length;
  25235. $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647);
  25236. normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
  25237. if (false === $str->string) {
  25238. throw new InvalidArgumentException('Invalid UTF-8 string.');
  25239. }
  25240. return $str;
  25241. }
  25242. public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
  25243. {
  25244. if (1 > $limit = $limit ?? 2147483647) {
  25245. throw new InvalidArgumentException('Split limit must be a positive integer.');
  25246. }
  25247. if ('' === $delimiter) {
  25248. throw new InvalidArgumentException('Split delimiter is empty.');
  25249. }
  25250. if (null !== $flags) {
  25251. return parent::split($delimiter.'u', $limit, $flags);
  25252. }
  25253. normalizer_is_normalized($delimiter) ?: $delimiter = normalizer_normalize($delimiter);
  25254. if (false === $delimiter) {
  25255. throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
  25256. }
  25257. $str = clone $this;
  25258. $tail = $this->string;
  25259. $chunks = [];
  25260. $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
  25261. while (1 < $limit && false !== $i = $indexOf($tail, $delimiter)) {
  25262. $str->string = grapheme_substr($tail, 0, $i);
  25263. $chunks[] = clone $str;
  25264. $tail = substr($tail, \strlen($str->string) + \strlen($delimiter));
  25265. --$limit;
  25266. }
  25267. $str->string = $tail;
  25268. $chunks[] = clone $str;
  25269. return $chunks;
  25270. }
  25271. public function startsWith($prefix): bool
  25272. {
  25273. if ($prefix instanceof AbstractString) {
  25274. $prefix = $prefix->string;
  25275. } elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
  25276. return parent::startsWith($prefix);
  25277. } else {
  25278. $prefix = (string) $prefix;
  25279. }
  25280. $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
  25281. normalizer_is_normalized($prefix, $form) ?: $prefix = normalizer_normalize($prefix, $form);
  25282. if ('' === $prefix || false === $prefix) {
  25283. return false;
  25284. }
  25285. if ($this->ignoreCase) {
  25286. return 0 === mb_stripos(grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8');
  25287. }
  25288. return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES);
  25289. }
  25290. public function __wakeup()
  25291. {
  25292. if (!\is_string($this->string)) {
  25293. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  25294. }
  25295. normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
  25296. }
  25297. public function __clone()
  25298. {
  25299. if (null === $this->ignoreCase) {
  25300. normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
  25301. }
  25302. $this->ignoreCase = false;
  25303. }
  25304. }
  25305. <?php
  25306. namespace Symfony\Component\String\Exception;
  25307. interface ExceptionInterface extends \Throwable
  25308. {
  25309. }
  25310. <?php
  25311. namespace Symfony\Component\String\Exception;
  25312. class RuntimeException extends \RuntimeException implements ExceptionInterface
  25313. {
  25314. }
  25315. <?php
  25316. namespace Symfony\Component\String\Exception;
  25317. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  25318. {
  25319. }
  25320. <?php
  25321. namespace Symfony\Component\String\Slugger;
  25322. use Symfony\Component\String\AbstractUnicodeString;
  25323. interface SluggerInterface
  25324. {
  25325. public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString;
  25326. }
  25327. <?php
  25328. namespace Symfony\Component\String\Slugger;
  25329. use Symfony\Component\String\AbstractUnicodeString;
  25330. use Symfony\Component\String\UnicodeString;
  25331. use Symfony\Contracts\Translation\LocaleAwareInterface;
  25332. if (!interface_exists(LocaleAwareInterface::class)) {
  25333. throw new \LogicException('You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".');
  25334. }
  25335. class AsciiSlugger implements SluggerInterface, LocaleAwareInterface
  25336. {
  25337. private const LOCALE_TO_TRANSLITERATOR_ID = [
  25338. 'am' => 'Amharic-Latin',
  25339. 'ar' => 'Arabic-Latin',
  25340. 'az' => 'Azerbaijani-Latin',
  25341. 'be' => 'Belarusian-Latin',
  25342. 'bg' => 'Bulgarian-Latin',
  25343. 'bn' => 'Bengali-Latin',
  25344. 'de' => 'de-ASCII',
  25345. 'el' => 'Greek-Latin',
  25346. 'fa' => 'Persian-Latin',
  25347. 'he' => 'Hebrew-Latin',
  25348. 'hy' => 'Armenian-Latin',
  25349. 'ka' => 'Georgian-Latin',
  25350. 'kk' => 'Kazakh-Latin',
  25351. 'ky' => 'Kirghiz-Latin',
  25352. 'ko' => 'Korean-Latin',
  25353. 'mk' => 'Macedonian-Latin',
  25354. 'mn' => 'Mongolian-Latin',
  25355. 'or' => 'Oriya-Latin',
  25356. 'ps' => 'Pashto-Latin',
  25357. 'ru' => 'Russian-Latin',
  25358. 'sr' => 'Serbian-Latin',
  25359. 'sr_Cyrl' => 'Serbian-Latin',
  25360. 'th' => 'Thai-Latin',
  25361. 'tk' => 'Turkmen-Latin',
  25362. 'uk' => 'Ukrainian-Latin',
  25363. 'uz' => 'Uzbek-Latin',
  25364. 'zh' => 'Han-Latin',
  25365. ];
  25366. private $defaultLocale;
  25367. private $symbolsMap = [
  25368. 'en' => ['@' => 'at', '&' => 'and'],
  25369. ];
  25370. private $transliterators = [];
  25371. public function __construct(?string $defaultLocale = null, $symbolsMap = null)
  25372. {
  25373. if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) {
  25374. throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolsMap)));
  25375. }
  25376. $this->defaultLocale = $defaultLocale;
  25377. $this->symbolsMap = $symbolsMap ?? $this->symbolsMap;
  25378. }
  25379. public function setLocale($locale)
  25380. {
  25381. $this->defaultLocale = $locale;
  25382. }
  25383. public function getLocale()
  25384. {
  25385. return $this->defaultLocale;
  25386. }
  25387. public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString
  25388. {
  25389. $locale = $locale ?? $this->defaultLocale;
  25390. $transliterator = [];
  25391. if ($locale && ('de' === $locale || 0 === strpos($locale, 'de_'))) {
  25392. $transliterator = ['de-ASCII'];
  25393. } elseif (\function_exists('transliterator_transliterate') && $locale) {
  25394. $transliterator = (array) $this->createTransliterator($locale);
  25395. }
  25396. if ($this->symbolsMap instanceof \Closure) {
  25397. $symbolsMap = $this->symbolsMap;
  25398. array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) {
  25399. return $symbolsMap($s, $locale);
  25400. });
  25401. }
  25402. $unicodeString = (new UnicodeString($string))->ascii($transliterator);
  25403. if (\is_array($this->symbolsMap)) {
  25404. $map = null;
  25405. if (isset($this->symbolsMap[$locale])) {
  25406. $map = $this->symbolsMap[$locale];
  25407. } else {
  25408. $parent = self::getParentLocale($locale);
  25409. if ($parent && isset($this->symbolsMap[$parent])) {
  25410. $map = $this->symbolsMap[$parent];
  25411. }
  25412. }
  25413. if ($map) {
  25414. foreach ($map as $char => $replace) {
  25415. $unicodeString = $unicodeString->replace($char, ' '.$replace.' ');
  25416. }
  25417. }
  25418. }
  25419. return $unicodeString
  25420. ->replaceMatches('/[^A-Za-z0-9]++/', $separator)
  25421. ->trim($separator)
  25422. ;
  25423. }
  25424. private function createTransliterator(string $locale): ?\Transliterator
  25425. {
  25426. if (\array_key_exists($locale, $this->transliterators)) {
  25427. return $this->transliterators[$locale];
  25428. }
  25429. if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) {
  25430. return $this->transliterators[$locale] = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id);
  25431. }
  25432. if (!$parent = self::getParentLocale($locale)) {
  25433. return $this->transliterators[$locale] = null;
  25434. }
  25435. if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) {
  25436. $transliterator = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id);
  25437. }
  25438. return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null;
  25439. }
  25440. private static function getParentLocale(?string $locale): ?string
  25441. {
  25442. if (!$locale) {
  25443. return null;
  25444. }
  25445. if (false === $str = strrchr($locale, '_')) {
  25446. return null;
  25447. }
  25448. return substr($locale, 0, -\strlen($str));
  25449. }
  25450. }
  25451. <?php
  25452. if (!function_exists('trigger_deprecation')) {
  25453. function trigger_deprecation(string $package, string $version, string $message, ...$args): void
  25454. {
  25455. @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
  25456. }
  25457. }
  25458. <?php
  25459. namespace Symfony\Contracts\Service;
  25460. interface ServiceSubscriberInterface
  25461. {
  25462. public static function getSubscribedServices();
  25463. }
  25464. <?php
  25465. namespace Symfony\Contracts\Service\Attribute;
  25466. use Symfony\Contracts\Service\ServiceSubscriberTrait;
  25467. #[\Attribute(\Attribute::TARGET_METHOD)]
  25468. final class SubscribedService
  25469. {
  25470. public function __construct(
  25471. public ?string $key = null
  25472. ) {
  25473. }
  25474. }
  25475. <?php
  25476. namespace Symfony\Contracts\Service\Attribute;
  25477. #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
  25478. final class Required
  25479. {
  25480. }
  25481. <?php
  25482. namespace Symfony\Contracts\Service;
  25483. interface ResetInterface
  25484. {
  25485. public function reset();
  25486. }
  25487. <?php
  25488. namespace Symfony\Contracts\Service;
  25489. use Psr\Container\ContainerInterface;
  25490. interface ServiceProviderInterface extends ContainerInterface
  25491. {
  25492. public function getProvidedServices(): array;
  25493. }
  25494. <?php
  25495. namespace Symfony\Contracts\Service;
  25496. use Psr\Container\ContainerInterface;
  25497. use Symfony\Contracts\Service\Attribute\SubscribedService;
  25498. trait ServiceSubscriberTrait
  25499. {
  25500. protected $container;
  25501. public static function getSubscribedServices(): array
  25502. {
  25503. $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];
  25504. $attributeOptIn = false;
  25505. if (\PHP_VERSION_ID >= 80000) {
  25506. foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
  25507. if (self::class !== $method->getDeclaringClass()->name) {
  25508. continue;
  25509. }
  25510. if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
  25511. continue;
  25512. }
  25513. if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
  25514. throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
  25515. }
  25516. if (!$returnType = $method->getReturnType()) {
  25517. throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
  25518. }
  25519. $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
  25520. if ($returnType->allowsNull()) {
  25521. $serviceId = '?'.$serviceId;
  25522. }
  25523. $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId;
  25524. $attributeOptIn = true;
  25525. }
  25526. }
  25527. if (!$attributeOptIn) {
  25528. foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
  25529. if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
  25530. continue;
  25531. }
  25532. if (self::class !== $method->getDeclaringClass()->name) {
  25533. continue;
  25534. }
  25535. if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) {
  25536. continue;
  25537. }
  25538. if ($returnType->isBuiltin()) {
  25539. continue;
  25540. }
  25541. if (\PHP_VERSION_ID >= 80000) {
  25542. trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class);
  25543. }
  25544. $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType);
  25545. }
  25546. }
  25547. return $services;
  25548. }
  25549. public function setContainer(ContainerInterface $container)
  25550. {
  25551. $ret = null;
  25552. if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
  25553. $ret = parent::setContainer($container);
  25554. }
  25555. $this->container = $container;
  25556. return $ret;
  25557. }
  25558. }
  25559. <?php
  25560. namespace Symfony\Contracts\Service;
  25561. use Psr\Container\ContainerExceptionInterface;
  25562. use Psr\Container\NotFoundExceptionInterface;
  25563. class_exists(ContainerExceptionInterface::class);
  25564. class_exists(NotFoundExceptionInterface::class);
  25565. trait ServiceLocatorTrait
  25566. {
  25567. private $factories;
  25568. private $loading = [];
  25569. private $providedTypes;
  25570. public function __construct(array $factories)
  25571. {
  25572. $this->factories = $factories;
  25573. }
  25574. public function has(string $id)
  25575. {
  25576. return isset($this->factories[$id]);
  25577. }
  25578. public function get(string $id)
  25579. {
  25580. if (!isset($this->factories[$id])) {
  25581. throw $this->createNotFoundException($id);
  25582. }
  25583. if (isset($this->loading[$id])) {
  25584. $ids = array_values($this->loading);
  25585. $ids = \array_slice($this->loading, array_search($id, $ids));
  25586. $ids[] = $id;
  25587. throw $this->createCircularReferenceException($id, $ids);
  25588. }
  25589. $this->loading[$id] = $id;
  25590. try {
  25591. return $this->factories[$id]($this);
  25592. } finally {
  25593. unset($this->loading[$id]);
  25594. }
  25595. }
  25596. public function getProvidedServices(): array
  25597. {
  25598. if (null === $this->providedTypes) {
  25599. $this->providedTypes = [];
  25600. foreach ($this->factories as $name => $factory) {
  25601. if (!\is_callable($factory)) {
  25602. $this->providedTypes[$name] = '?';
  25603. } else {
  25604. $type = (new \ReflectionFunction($factory))->getReturnType();
  25605. $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
  25606. }
  25607. }
  25608. }
  25609. return $this->providedTypes;
  25610. }
  25611. private function createNotFoundException(string $id): NotFoundExceptionInterface
  25612. {
  25613. if (!$alternatives = array_keys($this->factories)) {
  25614. $message = 'is empty...';
  25615. } else {
  25616. $last = array_pop($alternatives);
  25617. if ($alternatives) {
  25618. $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
  25619. } else {
  25620. $message = sprintf('only knows about the "%s" service.', $last);
  25621. }
  25622. }
  25623. if ($this->loading) {
  25624. $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
  25625. } else {
  25626. $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message);
  25627. }
  25628. return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
  25629. };
  25630. }
  25631. private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
  25632. {
  25633. return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
  25634. };
  25635. }
  25636. }
  25637. <?php
  25638. namespace Symfony\Component\Process;
  25639. class ExecutableFinder
  25640. {
  25641. private const CMD_BUILTINS = [
  25642. 'assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date',
  25643. 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto',
  25644. 'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause',
  25645. 'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set',
  25646. 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol',
  25647. ];
  25648. private $suffixes = [];
  25649. public function setSuffixes(array $suffixes)
  25650. {
  25651. $this->suffixes = $suffixes;
  25652. }
  25653. public function addSuffix(string $suffix)
  25654. {
  25655. $this->suffixes[] = $suffix;
  25656. }
  25657. public function find(string $name, ?string $default = null, array $extraDirs = [])
  25658. {
  25659. if ('\\' === \DIRECTORY_SEPARATOR && \in_array(strtolower($name), self::CMD_BUILTINS, true)) {
  25660. return $name;
  25661. }
  25662. $dirs = array_merge(
  25663. explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
  25664. $extraDirs
  25665. );
  25666. $suffixes = [];
  25667. if ('\\' === \DIRECTORY_SEPARATOR) {
  25668. $pathExt = getenv('PATHEXT');
  25669. $suffixes = $this->suffixes;
  25670. $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']);
  25671. }
  25672. $suffixes = '' !== pathinfo($name, PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']);
  25673. foreach ($suffixes as $suffix) {
  25674. foreach ($dirs as $dir) {
  25675. if ('' === $dir) {
  25676. $dir = '.';
  25677. }
  25678. if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
  25679. return $file;
  25680. }
  25681. if (!@is_dir($dir) && basename($dir) === $name.$suffix && @is_executable($dir)) {
  25682. return $dir;
  25683. }
  25684. }
  25685. }
  25686. if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('exec') || \strlen($name) !== strcspn($name, '/'.\DIRECTORY_SEPARATOR)) {
  25687. return $default;
  25688. }
  25689. $execResult = exec('command -v -- '.escapeshellarg($name));
  25690. if (($executablePath = substr($execResult, 0, strpos($execResult, \PHP_EOL) ?: null)) && @is_executable($executablePath)) {
  25691. return $executablePath;
  25692. }
  25693. return $default;
  25694. }
  25695. }
  25696. <?php
  25697. namespace Symfony\Component\Process\Pipes;
  25698. use Symfony\Component\Process\Process;
  25699. class UnixPipes extends AbstractPipes
  25700. {
  25701. private $ttyMode;
  25702. private $ptyMode;
  25703. private $haveReadSupport;
  25704. public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport)
  25705. {
  25706. $this->ttyMode = $ttyMode;
  25707. $this->ptyMode = $ptyMode;
  25708. $this->haveReadSupport = $haveReadSupport;
  25709. parent::__construct($input);
  25710. }
  25711. public function __sleep(): array
  25712. {
  25713. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  25714. }
  25715. public function __wakeup()
  25716. {
  25717. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  25718. }
  25719. public function __destruct()
  25720. {
  25721. $this->close();
  25722. }
  25723. public function getDescriptors(): array
  25724. {
  25725. if (!$this->haveReadSupport) {
  25726. $nullstream = fopen('/dev/null', 'c');
  25727. return [
  25728. ['pipe', 'r'],
  25729. $nullstream,
  25730. $nullstream,
  25731. ];
  25732. }
  25733. if ($this->ttyMode) {
  25734. return [
  25735. ['file', '/dev/tty', 'r'],
  25736. ['file', '/dev/tty', 'w'],
  25737. ['file', '/dev/tty', 'w'],
  25738. ];
  25739. }
  25740. if ($this->ptyMode && Process::isPtySupported()) {
  25741. return [
  25742. ['pty'],
  25743. ['pty'],
  25744. ['pty'],
  25745. ];
  25746. }
  25747. return [
  25748. ['pipe', 'r'],
  25749. ['pipe', 'w'],
  25750. ['pipe', 'w'],
  25751. ];
  25752. }
  25753. public function getFiles(): array
  25754. {
  25755. return [];
  25756. }
  25757. public function readAndWrite(bool $blocking, bool $close = false): array
  25758. {
  25759. $this->unblock();
  25760. $w = $this->write();
  25761. $read = $e = [];
  25762. $r = $this->pipes;
  25763. unset($r[0]);
  25764. set_error_handler([$this, 'handleError']);
  25765. if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
  25766. restore_error_handler();
  25767. if (!$this->hasSystemCallBeenInterrupted()) {
  25768. $this->pipes = [];
  25769. }
  25770. return $read;
  25771. }
  25772. restore_error_handler();
  25773. foreach ($r as $pipe) {
  25774. $read[$type = array_search($pipe, $this->pipes, true)] = '';
  25775. do {
  25776. $data = @fread($pipe, self::CHUNK_SIZE);
  25777. $read[$type] .= $data;
  25778. } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
  25779. if (!isset($read[$type][0])) {
  25780. unset($read[$type]);
  25781. }
  25782. if ($close && feof($pipe)) {
  25783. fclose($pipe);
  25784. unset($this->pipes[$type]);
  25785. }
  25786. }
  25787. return $read;
  25788. }
  25789. public function haveReadSupport(): bool
  25790. {
  25791. return $this->haveReadSupport;
  25792. }
  25793. public function areOpen(): bool
  25794. {
  25795. return (bool) $this->pipes;
  25796. }
  25797. }
  25798. <?php
  25799. namespace Symfony\Component\Process\Pipes;
  25800. use Symfony\Component\Process\Exception\RuntimeException;
  25801. use Symfony\Component\Process\Process;
  25802. class WindowsPipes extends AbstractPipes
  25803. {
  25804. private $files = [];
  25805. private $fileHandles = [];
  25806. private $lockHandles = [];
  25807. private $readBytes = [
  25808. Process::STDOUT => 0,
  25809. Process::STDERR => 0,
  25810. ];
  25811. private $haveReadSupport;
  25812. public function __construct($input, bool $haveReadSupport)
  25813. {
  25814. $this->haveReadSupport = $haveReadSupport;
  25815. if ($this->haveReadSupport) {
  25816. $pipes = [
  25817. Process::STDOUT => Process::OUT,
  25818. Process::STDERR => Process::ERR,
  25819. ];
  25820. $tmpDir = sys_get_temp_dir();
  25821. $lastError = 'unknown reason';
  25822. set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
  25823. for ($i = 0;; ++$i) {
  25824. foreach ($pipes as $pipe => $name) {
  25825. $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
  25826. if (!$h = fopen($file.'.lock', 'w')) {
  25827. if (file_exists($file.'.lock')) {
  25828. continue 2;
  25829. }
  25830. restore_error_handler();
  25831. throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
  25832. }
  25833. if (!flock($h, \LOCK_EX | \LOCK_NB)) {
  25834. continue 2;
  25835. }
  25836. if (isset($this->lockHandles[$pipe])) {
  25837. flock($this->lockHandles[$pipe], \LOCK_UN);
  25838. fclose($this->lockHandles[$pipe]);
  25839. }
  25840. $this->lockHandles[$pipe] = $h;
  25841. if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) {
  25842. flock($this->lockHandles[$pipe], \LOCK_UN);
  25843. fclose($this->lockHandles[$pipe]);
  25844. unset($this->lockHandles[$pipe]);
  25845. continue 2;
  25846. }
  25847. $this->fileHandles[$pipe] = $h;
  25848. $this->files[$pipe] = $file;
  25849. }
  25850. break;
  25851. }
  25852. restore_error_handler();
  25853. }
  25854. parent::__construct($input);
  25855. }
  25856. public function __sleep(): array
  25857. {
  25858. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  25859. }
  25860. public function __wakeup()
  25861. {
  25862. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  25863. }
  25864. public function __destruct()
  25865. {
  25866. $this->close();
  25867. }
  25868. public function getDescriptors(): array
  25869. {
  25870. if (!$this->haveReadSupport) {
  25871. $nullstream = fopen('NUL', 'c');
  25872. return [
  25873. ['pipe', 'r'],
  25874. $nullstream,
  25875. $nullstream,
  25876. ];
  25877. }
  25878. return [
  25879. ['pipe', 'r'],
  25880. ['file', 'NUL', 'w'],
  25881. ['file', 'NUL', 'w'],
  25882. ];
  25883. }
  25884. public function getFiles(): array
  25885. {
  25886. return $this->files;
  25887. }
  25888. public function readAndWrite(bool $blocking, bool $close = false): array
  25889. {
  25890. $this->unblock();
  25891. $w = $this->write();
  25892. $read = $r = $e = [];
  25893. if ($blocking) {
  25894. if ($w) {
  25895. @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
  25896. } elseif ($this->fileHandles) {
  25897. usleep((int) (Process::TIMEOUT_PRECISION * 1E6));
  25898. }
  25899. }
  25900. foreach ($this->fileHandles as $type => $fileHandle) {
  25901. $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
  25902. if (isset($data[0])) {
  25903. $this->readBytes[$type] += \strlen($data);
  25904. $read[$type] = $data;
  25905. }
  25906. if ($close) {
  25907. ftruncate($fileHandle, 0);
  25908. fclose($fileHandle);
  25909. flock($this->lockHandles[$type], \LOCK_UN);
  25910. fclose($this->lockHandles[$type]);
  25911. unset($this->fileHandles[$type], $this->lockHandles[$type]);
  25912. }
  25913. }
  25914. return $read;
  25915. }
  25916. public function haveReadSupport(): bool
  25917. {
  25918. return $this->haveReadSupport;
  25919. }
  25920. public function areOpen(): bool
  25921. {
  25922. return $this->pipes && $this->fileHandles;
  25923. }
  25924. public function close()
  25925. {
  25926. parent::close();
  25927. foreach ($this->fileHandles as $type => $handle) {
  25928. ftruncate($handle, 0);
  25929. fclose($handle);
  25930. flock($this->lockHandles[$type], \LOCK_UN);
  25931. fclose($this->lockHandles[$type]);
  25932. }
  25933. $this->fileHandles = $this->lockHandles = [];
  25934. }
  25935. }
  25936. <?php
  25937. namespace Symfony\Component\Process\Pipes;
  25938. use Symfony\Component\Process\Exception\InvalidArgumentException;
  25939. abstract class AbstractPipes implements PipesInterface
  25940. {
  25941. public $pipes = [];
  25942. private $inputBuffer = '';
  25943. private $input;
  25944. private $blocked = true;
  25945. private $lastError;
  25946. public function __construct($input)
  25947. {
  25948. if (\is_resource($input) || $input instanceof \Iterator) {
  25949. $this->input = $input;
  25950. } elseif (\is_string($input)) {
  25951. $this->inputBuffer = $input;
  25952. } else {
  25953. $this->inputBuffer = (string) $input;
  25954. }
  25955. }
  25956. public function close()
  25957. {
  25958. foreach ($this->pipes as $pipe) {
  25959. if (\is_resource($pipe)) {
  25960. fclose($pipe);
  25961. }
  25962. }
  25963. $this->pipes = [];
  25964. }
  25965. protected function hasSystemCallBeenInterrupted(): bool
  25966. {
  25967. $lastError = $this->lastError;
  25968. $this->lastError = null;
  25969. return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
  25970. }
  25971. protected function unblock()
  25972. {
  25973. if (!$this->blocked) {
  25974. return;
  25975. }
  25976. foreach ($this->pipes as $pipe) {
  25977. stream_set_blocking($pipe, 0);
  25978. }
  25979. if (\is_resource($this->input)) {
  25980. stream_set_blocking($this->input, 0);
  25981. }
  25982. $this->blocked = false;
  25983. }
  25984. protected function write(): ?array
  25985. {
  25986. if (!isset($this->pipes[0])) {
  25987. return null;
  25988. }
  25989. $input = $this->input;
  25990. if ($input instanceof \Iterator) {
  25991. if (!$input->valid()) {
  25992. $input = null;
  25993. } elseif (\is_resource($input = $input->current())) {
  25994. stream_set_blocking($input, 0);
  25995. } elseif (!isset($this->inputBuffer[0])) {
  25996. if (!\is_string($input)) {
  25997. if (!\is_scalar($input)) {
  25998. throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input)));
  25999. }
  26000. $input = (string) $input;
  26001. }
  26002. $this->inputBuffer = $input;
  26003. $this->input->next();
  26004. $input = null;
  26005. } else {
  26006. $input = null;
  26007. }
  26008. }
  26009. $r = $e = [];
  26010. $w = [$this->pipes[0]];
  26011. if (false === @stream_select($r, $w, $e, 0, 0)) {
  26012. return null;
  26013. }
  26014. foreach ($w as $stdin) {
  26015. if (isset($this->inputBuffer[0])) {
  26016. $written = fwrite($stdin, $this->inputBuffer);
  26017. $this->inputBuffer = substr($this->inputBuffer, $written);
  26018. if (isset($this->inputBuffer[0])) {
  26019. return [$this->pipes[0]];
  26020. }
  26021. }
  26022. if ($input) {
  26023. while (true) {
  26024. $data = fread($input, self::CHUNK_SIZE);
  26025. if (!isset($data[0])) {
  26026. break;
  26027. }
  26028. $written = fwrite($stdin, $data);
  26029. $data = substr($data, $written);
  26030. if (isset($data[0])) {
  26031. $this->inputBuffer = $data;
  26032. return [$this->pipes[0]];
  26033. }
  26034. }
  26035. if (feof($input)) {
  26036. if ($this->input instanceof \Iterator) {
  26037. $this->input->next();
  26038. } else {
  26039. $this->input = null;
  26040. }
  26041. }
  26042. }
  26043. }
  26044. if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
  26045. $this->input = null;
  26046. fclose($this->pipes[0]);
  26047. unset($this->pipes[0]);
  26048. } elseif (!$w) {
  26049. return [$this->pipes[0]];
  26050. }
  26051. return null;
  26052. }
  26053. public function handleError(int $type, string $msg)
  26054. {
  26055. $this->lastError = $msg;
  26056. }
  26057. }
  26058. <?php
  26059. namespace Symfony\Component\Process\Pipes;
  26060. interface PipesInterface
  26061. {
  26062. public const CHUNK_SIZE = 16384;
  26063. public function getDescriptors(): array;
  26064. public function getFiles(): array;
  26065. public function readAndWrite(bool $blocking, bool $close = false): array;
  26066. public function areOpen(): bool;
  26067. public function haveReadSupport(): bool;
  26068. public function close();
  26069. }
  26070. <?php
  26071. namespace Symfony\Component\Process;
  26072. use Symfony\Component\Process\Exception\RuntimeException;
  26073. /**
  26074. @implements
  26075. */
  26076. class InputStream implements \IteratorAggregate
  26077. {
  26078. private $onEmpty = null;
  26079. private $input = [];
  26080. private $open = true;
  26081. public function onEmpty(?callable $onEmpty = null)
  26082. {
  26083. $this->onEmpty = $onEmpty;
  26084. }
  26085. public function write($input)
  26086. {
  26087. if (null === $input) {
  26088. return;
  26089. }
  26090. if ($this->isClosed()) {
  26091. throw new RuntimeException(sprintf('"%s" is closed.', static::class));
  26092. }
  26093. $this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
  26094. }
  26095. public function close()
  26096. {
  26097. $this->open = false;
  26098. }
  26099. public function isClosed()
  26100. {
  26101. return !$this->open;
  26102. }
  26103. #[\ReturnTypeWillChange]
  26104. public function getIterator()
  26105. {
  26106. $this->open = true;
  26107. while ($this->open || $this->input) {
  26108. if (!$this->input) {
  26109. yield '';
  26110. continue;
  26111. }
  26112. $current = array_shift($this->input);
  26113. if ($current instanceof \Iterator) {
  26114. yield from $current;
  26115. } else {
  26116. yield $current;
  26117. }
  26118. if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
  26119. $this->write($onEmpty($this));
  26120. }
  26121. }
  26122. }
  26123. }
  26124. <?php
  26125. namespace Symfony\Component\Process;
  26126. use Symfony\Component\Process\Exception\LogicException;
  26127. use Symfony\Component\Process\Exception\RuntimeException;
  26128. class PhpProcess extends Process
  26129. {
  26130. public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null)
  26131. {
  26132. if (null === $php) {
  26133. $executableFinder = new PhpExecutableFinder();
  26134. $php = $executableFinder->find(false);
  26135. $php = false === $php ? null : array_merge([$php], $executableFinder->findArguments());
  26136. }
  26137. if ('phpdbg' === \PHP_SAPI) {
  26138. $file = tempnam(sys_get_temp_dir(), 'dbg');
  26139. file_put_contents($file, $script);
  26140. register_shutdown_function('unlink', $file);
  26141. $php[] = $file;
  26142. $script = null;
  26143. }
  26144. parent::__construct($php, $cwd, $env, $script, $timeout);
  26145. }
  26146. public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60)
  26147. {
  26148. throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
  26149. }
  26150. public function start(?callable $callback = null, array $env = [])
  26151. {
  26152. if (null === $this->getCommandLine()) {
  26153. throw new RuntimeException('Unable to find the PHP executable.');
  26154. }
  26155. parent::start($callback, $env);
  26156. }
  26157. }
  26158. <?php
  26159. namespace Symfony\Component\Process;
  26160. class PhpExecutableFinder
  26161. {
  26162. private $executableFinder;
  26163. public function __construct()
  26164. {
  26165. $this->executableFinder = new ExecutableFinder();
  26166. }
  26167. public function find(bool $includeArgs = true)
  26168. {
  26169. if ($php = getenv('PHP_BINARY')) {
  26170. if (!is_executable($php) && !$php = $this->executableFinder->find($php)) {
  26171. return false;
  26172. }
  26173. if (@is_dir($php)) {
  26174. return false;
  26175. }
  26176. return $php;
  26177. }
  26178. $args = $this->findArguments();
  26179. $args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
  26180. if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cli', 'cli-server', 'phpdbg'], true)) {
  26181. return \PHP_BINARY.$args;
  26182. }
  26183. if ($php = getenv('PHP_PATH')) {
  26184. if (!@is_executable($php) || @is_dir($php)) {
  26185. return false;
  26186. }
  26187. return $php;
  26188. }
  26189. if ($php = getenv('PHP_PEAR_PHP_BIN')) {
  26190. if (@is_executable($php) && !@is_dir($php)) {
  26191. return $php;
  26192. }
  26193. }
  26194. if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php')) && !@is_dir($php)) {
  26195. return $php;
  26196. }
  26197. $dirs = [\PHP_BINDIR];
  26198. if ('\\' === \DIRECTORY_SEPARATOR) {
  26199. $dirs[] = 'C:\xampp\php\\';
  26200. }
  26201. return $this->executableFinder->find('php', false, $dirs);
  26202. }
  26203. public function findArguments()
  26204. {
  26205. $arguments = [];
  26206. if ('phpdbg' === \PHP_SAPI) {
  26207. $arguments[] = '-qrr';
  26208. }
  26209. return $arguments;
  26210. }
  26211. }
  26212. <?php
  26213. namespace Symfony\Component\Process\Exception;
  26214. use Symfony\Component\Process\Process;
  26215. final class ProcessSignaledException extends RuntimeException
  26216. {
  26217. private $process;
  26218. public function __construct(Process $process)
  26219. {
  26220. $this->process = $process;
  26221. parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
  26222. }
  26223. public function getProcess(): Process
  26224. {
  26225. return $this->process;
  26226. }
  26227. public function getSignal(): int
  26228. {
  26229. return $this->getProcess()->getTermSignal();
  26230. }
  26231. }
  26232. <?php
  26233. namespace Symfony\Component\Process\Exception;
  26234. class LogicException extends \LogicException implements ExceptionInterface
  26235. {
  26236. }
  26237. <?php
  26238. namespace Symfony\Component\Process\Exception;
  26239. interface ExceptionInterface extends \Throwable
  26240. {
  26241. }
  26242. <?php
  26243. namespace Symfony\Component\Process\Exception;
  26244. use Symfony\Component\Process\Process;
  26245. class ProcessFailedException extends RuntimeException
  26246. {
  26247. private $process;
  26248. public function __construct(Process $process)
  26249. {
  26250. if ($process->isSuccessful()) {
  26251. throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
  26252. }
  26253. $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
  26254. $process->getCommandLine(),
  26255. $process->getExitCode(),
  26256. $process->getExitCodeText(),
  26257. $process->getWorkingDirectory()
  26258. );
  26259. if (!$process->isOutputDisabled()) {
  26260. $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
  26261. $process->getOutput(),
  26262. $process->getErrorOutput()
  26263. );
  26264. }
  26265. parent::__construct($error);
  26266. $this->process = $process;
  26267. }
  26268. public function getProcess()
  26269. {
  26270. return $this->process;
  26271. }
  26272. }
  26273. <?php
  26274. namespace Symfony\Component\Process\Exception;
  26275. class RuntimeException extends \RuntimeException implements ExceptionInterface
  26276. {
  26277. }
  26278. <?php
  26279. namespace Symfony\Component\Process\Exception;
  26280. use Symfony\Component\Process\Process;
  26281. class ProcessTimedOutException extends RuntimeException
  26282. {
  26283. public const TYPE_GENERAL = 1;
  26284. public const TYPE_IDLE = 2;
  26285. private $process;
  26286. private $timeoutType;
  26287. public function __construct(Process $process, int $timeoutType)
  26288. {
  26289. $this->process = $process;
  26290. $this->timeoutType = $timeoutType;
  26291. parent::__construct(sprintf(
  26292. 'The process "%s" exceeded the timeout of %s seconds.',
  26293. $process->getCommandLine(),
  26294. $this->getExceededTimeout()
  26295. ));
  26296. }
  26297. public function getProcess()
  26298. {
  26299. return $this->process;
  26300. }
  26301. public function isGeneralTimeout()
  26302. {
  26303. return self::TYPE_GENERAL === $this->timeoutType;
  26304. }
  26305. public function isIdleTimeout()
  26306. {
  26307. return self::TYPE_IDLE === $this->timeoutType;
  26308. }
  26309. public function getExceededTimeout()
  26310. {
  26311. switch ($this->timeoutType) {
  26312. case self::TYPE_GENERAL:
  26313. return $this->process->getTimeout();
  26314. case self::TYPE_IDLE:
  26315. return $this->process->getIdleTimeout();
  26316. default:
  26317. throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
  26318. }
  26319. }
  26320. }
  26321. <?php
  26322. namespace Symfony\Component\Process\Exception;
  26323. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  26324. {
  26325. }
  26326. <?php
  26327. namespace Symfony\Component\Process;
  26328. use Symfony\Component\Process\Exception\InvalidArgumentException;
  26329. class ProcessUtils
  26330. {
  26331. private function __construct()
  26332. {
  26333. }
  26334. public static function validateInput(string $caller, $input)
  26335. {
  26336. if (null !== $input) {
  26337. if (\is_resource($input)) {
  26338. return $input;
  26339. }
  26340. if (\is_string($input)) {
  26341. return $input;
  26342. }
  26343. if (\is_scalar($input)) {
  26344. return (string) $input;
  26345. }
  26346. if ($input instanceof Process) {
  26347. return $input->getIterator($input::ITER_SKIP_ERR);
  26348. }
  26349. if ($input instanceof \Iterator) {
  26350. return $input;
  26351. }
  26352. if ($input instanceof \Traversable) {
  26353. return new \IteratorIterator($input);
  26354. }
  26355. throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
  26356. }
  26357. return $input;
  26358. }
  26359. }
  26360. <?php
  26361. namespace Symfony\Component\Process;
  26362. use Symfony\Component\Process\Exception\InvalidArgumentException;
  26363. use Symfony\Component\Process\Exception\LogicException;
  26364. use Symfony\Component\Process\Exception\ProcessFailedException;
  26365. use Symfony\Component\Process\Exception\ProcessSignaledException;
  26366. use Symfony\Component\Process\Exception\ProcessTimedOutException;
  26367. use Symfony\Component\Process\Exception\RuntimeException;
  26368. use Symfony\Component\Process\Pipes\PipesInterface;
  26369. use Symfony\Component\Process\Pipes\UnixPipes;
  26370. use Symfony\Component\Process\Pipes\WindowsPipes;
  26371. /**
  26372. @implements
  26373. */
  26374. class Process implements \IteratorAggregate
  26375. {
  26376. public const ERR = 'err';
  26377. public const OUT = 'out';
  26378. public const STATUS_READY = 'ready';
  26379. public const STATUS_STARTED = 'started';
  26380. public const STATUS_TERMINATED = 'terminated';
  26381. public const STDIN = 0;
  26382. public const STDOUT = 1;
  26383. public const STDERR = 2;
  26384. public const TIMEOUT_PRECISION = 0.2;
  26385. public const ITER_NON_BLOCKING = 1;
  26386. public const ITER_KEEP_OUTPUT = 2;
  26387. public const ITER_SKIP_OUT = 4;
  26388. public const ITER_SKIP_ERR = 8;
  26389. private $callback;
  26390. private $hasCallback = false;
  26391. private $commandline;
  26392. private $cwd;
  26393. private $env = [];
  26394. private $input;
  26395. private $starttime;
  26396. private $lastOutputTime;
  26397. private $timeout;
  26398. private $idleTimeout;
  26399. private $exitcode;
  26400. private $fallbackStatus = [];
  26401. private $processInformation;
  26402. private $outputDisabled = false;
  26403. private $stdout;
  26404. private $stderr;
  26405. private $process;
  26406. private $status = self::STATUS_READY;
  26407. private $incrementalOutputOffset = 0;
  26408. private $incrementalErrorOutputOffset = 0;
  26409. private $tty = false;
  26410. private $pty;
  26411. private $options = ['suppress_errors' => true, 'bypass_shell' => true];
  26412. private $useFileHandles = false;
  26413. private $processPipes;
  26414. private $latestSignal;
  26415. private $cachedExitCode;
  26416. private static $sigchild;
  26417. public static $exitCodes = [
  26418. 0 => 'OK',
  26419. 1 => 'General error',
  26420. 2 => 'Misuse of shell builtins',
  26421. 126 => 'Invoked command cannot execute',
  26422. 127 => 'Command not found',
  26423. 128 => 'Invalid exit argument',
  26424. 129 => 'Hangup',
  26425. 130 => 'Interrupt',
  26426. 131 => 'Quit and dump core',
  26427. 132 => 'Illegal instruction',
  26428. 133 => 'Trace/breakpoint trap',
  26429. 134 => 'Process aborted',
  26430. 135 => 'Bus error: "access to undefined portion of memory object"',
  26431. 136 => 'Floating point exception: "erroneous arithmetic operation"',
  26432. 137 => 'Kill (terminate immediately)',
  26433. 138 => 'User-defined 1',
  26434. 139 => 'Segmentation violation',
  26435. 140 => 'User-defined 2',
  26436. 141 => 'Write to pipe with no one reading',
  26437. 142 => 'Signal raised by alarm',
  26438. 143 => 'Termination (request to terminate)',
  26439. 145 => 'Child process terminated, stopped (or continued*)',
  26440. 146 => 'Continue if stopped',
  26441. 147 => 'Stop executing temporarily',
  26442. 148 => 'Terminal stop signal',
  26443. 149 => 'Background process attempting to read from tty ("in")',
  26444. 150 => 'Background process attempting to write to tty ("out")',
  26445. 151 => 'Urgent data available on socket',
  26446. 152 => 'CPU time limit exceeded',
  26447. 153 => 'File size limit exceeded',
  26448. 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
  26449. 155 => 'Profiling timer expired',
  26450. 157 => 'Pollable event',
  26451. 159 => 'Bad syscall',
  26452. ];
  26453. public function __construct(array $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60)
  26454. {
  26455. if (!\function_exists('proc_open')) {
  26456. throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
  26457. }
  26458. $this->commandline = $command;
  26459. $this->cwd = $cwd;
  26460. if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
  26461. $this->cwd = getcwd();
  26462. }
  26463. if (null !== $env) {
  26464. $this->setEnv($env);
  26465. }
  26466. $this->setInput($input);
  26467. $this->setTimeout($timeout);
  26468. $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
  26469. $this->pty = false;
  26470. }
  26471. public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60)
  26472. {
  26473. $process = new static([], $cwd, $env, $input, $timeout);
  26474. $process->commandline = $command;
  26475. return $process;
  26476. }
  26477. public function __sleep()
  26478. {
  26479. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  26480. }
  26481. public function __wakeup()
  26482. {
  26483. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  26484. }
  26485. public function __destruct()
  26486. {
  26487. if ($this->options['create_new_console'] ?? false) {
  26488. $this->processPipes->close();
  26489. } else {
  26490. $this->stop(0);
  26491. }
  26492. }
  26493. public function __clone()
  26494. {
  26495. $this->resetProcessData();
  26496. }
  26497. public function run(?callable $callback = null, array $env = []): int
  26498. {
  26499. $this->start($callback, $env);
  26500. return $this->wait();
  26501. }
  26502. public function mustRun(?callable $callback = null, array $env = []): self
  26503. {
  26504. if (0 !== $this->run($callback, $env)) {
  26505. throw new ProcessFailedException($this);
  26506. }
  26507. return $this;
  26508. }
  26509. public function start(?callable $callback = null, array $env = [])
  26510. {
  26511. if ($this->isRunning()) {
  26512. throw new RuntimeException('Process is already running.');
  26513. }
  26514. $this->resetProcessData();
  26515. $this->starttime = $this->lastOutputTime = microtime(true);
  26516. $this->callback = $this->buildCallback($callback);
  26517. $this->hasCallback = null !== $callback;
  26518. $descriptors = $this->getDescriptors();
  26519. if ($this->env) {
  26520. $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env;
  26521. }
  26522. $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv();
  26523. if (\is_array($commandline = $this->commandline)) {
  26524. $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
  26525. if ('\\' !== \DIRECTORY_SEPARATOR) {
  26526. $commandline = 'exec '.$commandline;
  26527. }
  26528. } else {
  26529. $commandline = $this->replacePlaceholders($commandline, $env);
  26530. }
  26531. if ('\\' === \DIRECTORY_SEPARATOR) {
  26532. $commandline = $this->prepareWindowsCommandLine($commandline, $env);
  26533. } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
  26534. $descriptors[3] = ['pipe', 'w'];
  26535. $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
  26536. $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code';
  26537. $ptsWorkaround = fopen(__FILE__, 'r');
  26538. }
  26539. $envPairs = [];
  26540. foreach ($env as $k => $v) {
  26541. if (false !== $v && false === \in_array($k, ['argc', 'argv', 'ARGC', 'ARGV'], true)) {
  26542. $envPairs[] = $k.'='.$v;
  26543. }
  26544. }
  26545. if (!is_dir($this->cwd)) {
  26546. throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
  26547. }
  26548. $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
  26549. if (!$this->process) {
  26550. throw new RuntimeException('Unable to launch a new process.');
  26551. }
  26552. $this->status = self::STATUS_STARTED;
  26553. if (isset($descriptors[3])) {
  26554. $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
  26555. }
  26556. if ($this->tty) {
  26557. return;
  26558. }
  26559. $this->updateStatus(false);
  26560. $this->checkTimeout();
  26561. }
  26562. public function restart(?callable $callback = null, array $env = []): self
  26563. {
  26564. if ($this->isRunning()) {
  26565. throw new RuntimeException('Process is already running.');
  26566. }
  26567. $process = clone $this;
  26568. $process->start($callback, $env);
  26569. return $process;
  26570. }
  26571. public function wait(?callable $callback = null)
  26572. {
  26573. $this->requireProcessIsStarted(__FUNCTION__);
  26574. $this->updateStatus(false);
  26575. if (null !== $callback) {
  26576. if (!$this->processPipes->haveReadSupport()) {
  26577. $this->stop(0);
  26578. throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
  26579. }
  26580. $this->callback = $this->buildCallback($callback);
  26581. }
  26582. do {
  26583. $this->checkTimeout();
  26584. $running = $this->isRunning() && ('\\' === \DIRECTORY_SEPARATOR || $this->processPipes->areOpen());
  26585. $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  26586. } while ($running);
  26587. while ($this->isRunning()) {
  26588. $this->checkTimeout();
  26589. usleep(1000);
  26590. }
  26591. if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
  26592. throw new ProcessSignaledException($this);
  26593. }
  26594. return $this->exitcode;
  26595. }
  26596. public function waitUntil(callable $callback): bool
  26597. {
  26598. $this->requireProcessIsStarted(__FUNCTION__);
  26599. $this->updateStatus(false);
  26600. if (!$this->processPipes->haveReadSupport()) {
  26601. $this->stop(0);
  26602. throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
  26603. }
  26604. $callback = $this->buildCallback($callback);
  26605. $ready = false;
  26606. while (true) {
  26607. $this->checkTimeout();
  26608. $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
  26609. $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  26610. foreach ($output as $type => $data) {
  26611. if (3 !== $type) {
  26612. $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
  26613. } elseif (!isset($this->fallbackStatus['signaled'])) {
  26614. $this->fallbackStatus['exitcode'] = (int) $data;
  26615. }
  26616. }
  26617. if ($ready) {
  26618. return true;
  26619. }
  26620. if (!$running) {
  26621. return false;
  26622. }
  26623. usleep(1000);
  26624. }
  26625. }
  26626. public function getPid()
  26627. {
  26628. return $this->isRunning() ? $this->processInformation['pid'] : null;
  26629. }
  26630. public function signal(int $signal)
  26631. {
  26632. $this->doSignal($signal, true);
  26633. return $this;
  26634. }
  26635. public function disableOutput()
  26636. {
  26637. if ($this->isRunning()) {
  26638. throw new RuntimeException('Disabling output while the process is running is not possible.');
  26639. }
  26640. if (null !== $this->idleTimeout) {
  26641. throw new LogicException('Output cannot be disabled while an idle timeout is set.');
  26642. }
  26643. $this->outputDisabled = true;
  26644. return $this;
  26645. }
  26646. public function enableOutput()
  26647. {
  26648. if ($this->isRunning()) {
  26649. throw new RuntimeException('Enabling output while the process is running is not possible.');
  26650. }
  26651. $this->outputDisabled = false;
  26652. return $this;
  26653. }
  26654. public function isOutputDisabled()
  26655. {
  26656. return $this->outputDisabled;
  26657. }
  26658. public function getOutput()
  26659. {
  26660. $this->readPipesForOutput(__FUNCTION__);
  26661. if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
  26662. return '';
  26663. }
  26664. return $ret;
  26665. }
  26666. public function getIncrementalOutput()
  26667. {
  26668. $this->readPipesForOutput(__FUNCTION__);
  26669. $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
  26670. $this->incrementalOutputOffset = ftell($this->stdout);
  26671. if (false === $latest) {
  26672. return '';
  26673. }
  26674. return $latest;
  26675. }
  26676. #[\ReturnTypeWillChange]
  26677. public function getIterator(int $flags = 0)
  26678. {
  26679. $this->readPipesForOutput(__FUNCTION__, false);
  26680. $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
  26681. $blocking = !(self::ITER_NON_BLOCKING & $flags);
  26682. $yieldOut = !(self::ITER_SKIP_OUT & $flags);
  26683. $yieldErr = !(self::ITER_SKIP_ERR & $flags);
  26684. while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
  26685. if ($yieldOut) {
  26686. $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
  26687. if (isset($out[0])) {
  26688. if ($clearOutput) {
  26689. $this->clearOutput();
  26690. } else {
  26691. $this->incrementalOutputOffset = ftell($this->stdout);
  26692. }
  26693. yield self::OUT => $out;
  26694. }
  26695. }
  26696. if ($yieldErr) {
  26697. $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
  26698. if (isset($err[0])) {
  26699. if ($clearOutput) {
  26700. $this->clearErrorOutput();
  26701. } else {
  26702. $this->incrementalErrorOutputOffset = ftell($this->stderr);
  26703. }
  26704. yield self::ERR => $err;
  26705. }
  26706. }
  26707. if (!$blocking && !isset($out[0]) && !isset($err[0])) {
  26708. yield self::OUT => '';
  26709. }
  26710. $this->checkTimeout();
  26711. $this->readPipesForOutput(__FUNCTION__, $blocking);
  26712. }
  26713. }
  26714. public function clearOutput()
  26715. {
  26716. ftruncate($this->stdout, 0);
  26717. fseek($this->stdout, 0);
  26718. $this->incrementalOutputOffset = 0;
  26719. return $this;
  26720. }
  26721. public function getErrorOutput()
  26722. {
  26723. $this->readPipesForOutput(__FUNCTION__);
  26724. if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
  26725. return '';
  26726. }
  26727. return $ret;
  26728. }
  26729. public function getIncrementalErrorOutput()
  26730. {
  26731. $this->readPipesForOutput(__FUNCTION__);
  26732. $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
  26733. $this->incrementalErrorOutputOffset = ftell($this->stderr);
  26734. if (false === $latest) {
  26735. return '';
  26736. }
  26737. return $latest;
  26738. }
  26739. public function clearErrorOutput()
  26740. {
  26741. ftruncate($this->stderr, 0);
  26742. fseek($this->stderr, 0);
  26743. $this->incrementalErrorOutputOffset = 0;
  26744. return $this;
  26745. }
  26746. public function getExitCode()
  26747. {
  26748. $this->updateStatus(false);
  26749. return $this->exitcode;
  26750. }
  26751. public function getExitCodeText()
  26752. {
  26753. if (null === $exitcode = $this->getExitCode()) {
  26754. return null;
  26755. }
  26756. return self::$exitCodes[$exitcode] ?? 'Unknown error';
  26757. }
  26758. public function isSuccessful()
  26759. {
  26760. return 0 === $this->getExitCode();
  26761. }
  26762. public function hasBeenSignaled()
  26763. {
  26764. $this->requireProcessIsTerminated(__FUNCTION__);
  26765. return $this->processInformation['signaled'];
  26766. }
  26767. public function getTermSignal()
  26768. {
  26769. $this->requireProcessIsTerminated(__FUNCTION__);
  26770. if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
  26771. throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.');
  26772. }
  26773. return $this->processInformation['termsig'];
  26774. }
  26775. public function hasBeenStopped()
  26776. {
  26777. $this->requireProcessIsTerminated(__FUNCTION__);
  26778. return $this->processInformation['stopped'];
  26779. }
  26780. public function getStopSignal()
  26781. {
  26782. $this->requireProcessIsTerminated(__FUNCTION__);
  26783. return $this->processInformation['stopsig'];
  26784. }
  26785. public function isRunning()
  26786. {
  26787. if (self::STATUS_STARTED !== $this->status) {
  26788. return false;
  26789. }
  26790. $this->updateStatus(false);
  26791. return $this->processInformation['running'];
  26792. }
  26793. public function isStarted()
  26794. {
  26795. return self::STATUS_READY != $this->status;
  26796. }
  26797. public function isTerminated()
  26798. {
  26799. $this->updateStatus(false);
  26800. return self::STATUS_TERMINATED == $this->status;
  26801. }
  26802. public function getStatus()
  26803. {
  26804. $this->updateStatus(false);
  26805. return $this->status;
  26806. }
  26807. public function stop(float $timeout = 10, ?int $signal = null)
  26808. {
  26809. $timeoutMicro = microtime(true) + $timeout;
  26810. if ($this->isRunning()) {
  26811. $this->doSignal(15, false);
  26812. do {
  26813. usleep(1000);
  26814. } while ($this->isRunning() && microtime(true) < $timeoutMicro);
  26815. if ($this->isRunning()) {
  26816. $this->doSignal($signal ?: 9, false);
  26817. }
  26818. }
  26819. if ($this->isRunning()) {
  26820. if (isset($this->fallbackStatus['pid'])) {
  26821. unset($this->fallbackStatus['pid']);
  26822. return $this->stop(0, $signal);
  26823. }
  26824. $this->close();
  26825. }
  26826. return $this->exitcode;
  26827. }
  26828. public function addOutput(string $line)
  26829. {
  26830. $this->lastOutputTime = microtime(true);
  26831. fseek($this->stdout, 0, \SEEK_END);
  26832. fwrite($this->stdout, $line);
  26833. fseek($this->stdout, $this->incrementalOutputOffset);
  26834. }
  26835. public function addErrorOutput(string $line)
  26836. {
  26837. $this->lastOutputTime = microtime(true);
  26838. fseek($this->stderr, 0, \SEEK_END);
  26839. fwrite($this->stderr, $line);
  26840. fseek($this->stderr, $this->incrementalErrorOutputOffset);
  26841. }
  26842. public function getLastOutputTime(): ?float
  26843. {
  26844. return $this->lastOutputTime;
  26845. }
  26846. public function getCommandLine()
  26847. {
  26848. return \is_array($this->commandline) ? implode(' ', array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
  26849. }
  26850. public function getTimeout()
  26851. {
  26852. return $this->timeout;
  26853. }
  26854. public function getIdleTimeout()
  26855. {
  26856. return $this->idleTimeout;
  26857. }
  26858. public function setTimeout(?float $timeout)
  26859. {
  26860. $this->timeout = $this->validateTimeout($timeout);
  26861. return $this;
  26862. }
  26863. public function setIdleTimeout(?float $timeout)
  26864. {
  26865. if (null !== $timeout && $this->outputDisabled) {
  26866. throw new LogicException('Idle timeout cannot be set while the output is disabled.');
  26867. }
  26868. $this->idleTimeout = $this->validateTimeout($timeout);
  26869. return $this;
  26870. }
  26871. public function setTty(bool $tty)
  26872. {
  26873. if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
  26874. throw new RuntimeException('TTY mode is not supported on Windows platform.');
  26875. }
  26876. if ($tty && !self::isTtySupported()) {
  26877. throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
  26878. }
  26879. $this->tty = $tty;
  26880. return $this;
  26881. }
  26882. public function isTty()
  26883. {
  26884. return $this->tty;
  26885. }
  26886. public function setPty(bool $bool)
  26887. {
  26888. $this->pty = $bool;
  26889. return $this;
  26890. }
  26891. public function isPty()
  26892. {
  26893. return $this->pty;
  26894. }
  26895. public function getWorkingDirectory()
  26896. {
  26897. if (null === $this->cwd) {
  26898. return getcwd() ?: null;
  26899. }
  26900. return $this->cwd;
  26901. }
  26902. public function setWorkingDirectory(string $cwd)
  26903. {
  26904. $this->cwd = $cwd;
  26905. return $this;
  26906. }
  26907. public function getEnv()
  26908. {
  26909. return $this->env;
  26910. }
  26911. public function setEnv(array $env)
  26912. {
  26913. $this->env = $env;
  26914. return $this;
  26915. }
  26916. public function getInput()
  26917. {
  26918. return $this->input;
  26919. }
  26920. public function setInput($input)
  26921. {
  26922. if ($this->isRunning()) {
  26923. throw new LogicException('Input cannot be set while the process is running.');
  26924. }
  26925. $this->input = ProcessUtils::validateInput(__METHOD__, $input);
  26926. return $this;
  26927. }
  26928. public function checkTimeout()
  26929. {
  26930. if (self::STATUS_STARTED !== $this->status) {
  26931. return;
  26932. }
  26933. if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
  26934. $this->stop(0);
  26935. throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
  26936. }
  26937. if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
  26938. $this->stop(0);
  26939. throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
  26940. }
  26941. }
  26942. public function getStartTime(): float
  26943. {
  26944. if (!$this->isStarted()) {
  26945. throw new LogicException('Start time is only available after process start.');
  26946. }
  26947. return $this->starttime;
  26948. }
  26949. public function setOptions(array $options)
  26950. {
  26951. if ($this->isRunning()) {
  26952. throw new RuntimeException('Setting options while the process is running is not possible.');
  26953. }
  26954. $defaultOptions = $this->options;
  26955. $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
  26956. foreach ($options as $key => $value) {
  26957. if (!\in_array($key, $existingOptions)) {
  26958. $this->options = $defaultOptions;
  26959. throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
  26960. }
  26961. $this->options[$key] = $value;
  26962. }
  26963. }
  26964. public static function isTtySupported(): bool
  26965. {
  26966. static $isTtySupported;
  26967. if (null === $isTtySupported) {
  26968. $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
  26969. }
  26970. return $isTtySupported;
  26971. }
  26972. public static function isPtySupported()
  26973. {
  26974. static $result;
  26975. if (null !== $result) {
  26976. return $result;
  26977. }
  26978. if ('\\' === \DIRECTORY_SEPARATOR) {
  26979. return $result = false;
  26980. }
  26981. return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
  26982. }
  26983. private function getDescriptors(): array
  26984. {
  26985. if ($this->input instanceof \Iterator) {
  26986. $this->input->rewind();
  26987. }
  26988. if ('\\' === \DIRECTORY_SEPARATOR) {
  26989. $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
  26990. } else {
  26991. $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
  26992. }
  26993. return $this->processPipes->getDescriptors();
  26994. }
  26995. protected function buildCallback(?callable $callback = null)
  26996. {
  26997. if ($this->outputDisabled) {
  26998. return function ($type, $data) use ($callback): bool {
  26999. return null !== $callback && $callback($type, $data);
  27000. };
  27001. }
  27002. $out = self::OUT;
  27003. return function ($type, $data) use ($callback, $out): bool {
  27004. if ($out == $type) {
  27005. $this->addOutput($data);
  27006. } else {
  27007. $this->addErrorOutput($data);
  27008. }
  27009. return null !== $callback && $callback($type, $data);
  27010. };
  27011. }
  27012. protected function updateStatus(bool $blocking)
  27013. {
  27014. if (self::STATUS_STARTED !== $this->status) {
  27015. return;
  27016. }
  27017. $this->processInformation = proc_get_status($this->process);
  27018. $running = $this->processInformation['running'];
  27019. if (\PHP_VERSION_ID < 80300) {
  27020. if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) {
  27021. $this->cachedExitCode = $this->processInformation['exitcode'];
  27022. }
  27023. if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) {
  27024. $this->processInformation['exitcode'] = $this->cachedExitCode;
  27025. }
  27026. }
  27027. $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  27028. if ($this->fallbackStatus && $this->isSigchildEnabled()) {
  27029. $this->processInformation = $this->fallbackStatus + $this->processInformation;
  27030. }
  27031. if (!$running) {
  27032. $this->close();
  27033. }
  27034. }
  27035. protected function isSigchildEnabled()
  27036. {
  27037. if (null !== self::$sigchild) {
  27038. return self::$sigchild;
  27039. }
  27040. if (!\function_exists('phpinfo')) {
  27041. return self::$sigchild = false;
  27042. }
  27043. ob_start();
  27044. phpinfo(\INFO_GENERAL);
  27045. return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
  27046. }
  27047. private function readPipesForOutput(string $caller, bool $blocking = false)
  27048. {
  27049. if ($this->outputDisabled) {
  27050. throw new LogicException('Output has been disabled.');
  27051. }
  27052. $this->requireProcessIsStarted($caller);
  27053. $this->updateStatus($blocking);
  27054. }
  27055. private function validateTimeout(?float $timeout): ?float
  27056. {
  27057. $timeout = (float) $timeout;
  27058. if (0.0 === $timeout) {
  27059. $timeout = null;
  27060. } elseif ($timeout < 0) {
  27061. throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
  27062. }
  27063. return $timeout;
  27064. }
  27065. private function readPipes(bool $blocking, bool $close)
  27066. {
  27067. $result = $this->processPipes->readAndWrite($blocking, $close);
  27068. $callback = $this->callback;
  27069. foreach ($result as $type => $data) {
  27070. if (3 !== $type) {
  27071. $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
  27072. } elseif (!isset($this->fallbackStatus['signaled'])) {
  27073. $this->fallbackStatus['exitcode'] = (int) $data;
  27074. }
  27075. }
  27076. }
  27077. private function close(): int
  27078. {
  27079. $this->processPipes->close();
  27080. if ($this->process) {
  27081. proc_close($this->process);
  27082. $this->process = null;
  27083. }
  27084. $this->exitcode = $this->processInformation['exitcode'];
  27085. $this->status = self::STATUS_TERMINATED;
  27086. if (-1 === $this->exitcode) {
  27087. if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
  27088. $this->exitcode = 128 + $this->processInformation['termsig'];
  27089. } elseif ($this->isSigchildEnabled()) {
  27090. $this->processInformation['signaled'] = true;
  27091. $this->processInformation['termsig'] = -1;
  27092. }
  27093. }
  27094. $this->callback = null;
  27095. return $this->exitcode;
  27096. }
  27097. private function resetProcessData()
  27098. {
  27099. $this->starttime = null;
  27100. $this->callback = null;
  27101. $this->exitcode = null;
  27102. $this->fallbackStatus = [];
  27103. $this->processInformation = null;
  27104. $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
  27105. $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
  27106. $this->process = null;
  27107. $this->latestSignal = null;
  27108. $this->status = self::STATUS_READY;
  27109. $this->incrementalOutputOffset = 0;
  27110. $this->incrementalErrorOutputOffset = 0;
  27111. }
  27112. private function doSignal(int $signal, bool $throwException): bool
  27113. {
  27114. if (null === $pid = $this->getPid()) {
  27115. if ($throwException) {
  27116. throw new LogicException('Cannot send signal on a non running process.');
  27117. }
  27118. return false;
  27119. }
  27120. if ('\\' === \DIRECTORY_SEPARATOR) {
  27121. exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
  27122. if ($exitCode && $this->isRunning()) {
  27123. if ($throwException) {
  27124. throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
  27125. }
  27126. return false;
  27127. }
  27128. } else {
  27129. if (!$this->isSigchildEnabled()) {
  27130. $ok = @proc_terminate($this->process, $signal);
  27131. } elseif (\function_exists('posix_kill')) {
  27132. $ok = @posix_kill($pid, $signal);
  27133. } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
  27134. $ok = false === fgets($pipes[2]);
  27135. }
  27136. if (!$ok) {
  27137. if ($throwException) {
  27138. throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal));
  27139. }
  27140. return false;
  27141. }
  27142. }
  27143. $this->latestSignal = $signal;
  27144. $this->fallbackStatus['signaled'] = true;
  27145. $this->fallbackStatus['exitcode'] = -1;
  27146. $this->fallbackStatus['termsig'] = $this->latestSignal;
  27147. return true;
  27148. }
  27149. private function prepareWindowsCommandLine(string $cmd, array &$env): string
  27150. {
  27151. $uid = uniqid('', true);
  27152. $varCount = 0;
  27153. $varCache = [];
  27154. $cmd = preg_replace_callback(
  27155. '/"(?:(
  27156. [^"%!^]*+
  27157. (?:
  27158. (?: !LF! | "(?:\^[%!^])?+" )
  27159. [^"%!^]*+
  27160. )++
  27161. ) | [^"]*+ )"/x',
  27162. function ($m) use (&$env, &$varCache, &$varCount, $uid) {
  27163. if (!isset($m[1])) {
  27164. return $m[0];
  27165. }
  27166. if (isset($varCache[$m[0]])) {
  27167. return $varCache[$m[0]];
  27168. }
  27169. if (str_contains($value = $m[1], "\0")) {
  27170. $value = str_replace("\0", '?', $value);
  27171. }
  27172. if (false === strpbrk($value, "\"%!\n")) {
  27173. return '"'.$value.'"';
  27174. }
  27175. $value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
  27176. $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
  27177. $var = $uid.++$varCount;
  27178. $env[$var] = $value;
  27179. return $varCache[$m[0]] = '!'.$var.'!';
  27180. },
  27181. $cmd
  27182. );
  27183. static $comSpec;
  27184. if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) {
  27185. $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec) .'"';
  27186. }
  27187. $cmd = ($comSpec ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
  27188. foreach ($this->processPipes->getFiles() as $offset => $filename) {
  27189. $cmd .= ' '.$offset.'>"'.$filename.'"';
  27190. }
  27191. return $cmd;
  27192. }
  27193. private function requireProcessIsStarted(string $functionName)
  27194. {
  27195. if (!$this->isStarted()) {
  27196. throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName));
  27197. }
  27198. }
  27199. private function requireProcessIsTerminated(string $functionName)
  27200. {
  27201. if (!$this->isTerminated()) {
  27202. throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName));
  27203. }
  27204. }
  27205. private function escapeArgument(?string $argument): string
  27206. {
  27207. if ('' === $argument || null === $argument) {
  27208. return '""';
  27209. }
  27210. if ('\\' !== \DIRECTORY_SEPARATOR) {
  27211. return "'".str_replace("'", "'\\''", $argument)."'";
  27212. }
  27213. if (str_contains($argument, "\0")) {
  27214. $argument = str_replace("\0", '?', $argument);
  27215. }
  27216. if (!preg_match('/[()%!^"<>&|\s]/', $argument)) {
  27217. return $argument;
  27218. }
  27219. $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
  27220. return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
  27221. }
  27222. private function replacePlaceholders(string $commandline, array $env)
  27223. {
  27224. return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
  27225. if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
  27226. throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
  27227. }
  27228. return $this->escapeArgument($env[$matches[1]]);
  27229. }, $commandline);
  27230. }
  27231. private function getDefaultEnv(): array
  27232. {
  27233. $env = getenv();
  27234. $env = ('\\' === \DIRECTORY_SEPARATOR ? array_intersect_ukey($env, $_SERVER, 'strcasecmp') : array_intersect_key($env, $_SERVER)) ?: $env;
  27235. return $_ENV + ('\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($env, $_ENV, 'strcasecmp') : $env);
  27236. }
  27237. }
  27238. <?php
  27239. namespace Symfony\Component\Console;
  27240. use Symfony\Component\Console\Event\ConsoleCommandEvent;
  27241. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  27242. use Symfony\Component\Console\Event\ConsoleSignalEvent;
  27243. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  27244. final class ConsoleEvents
  27245. {
  27246. /**
  27247. @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
  27248. */
  27249. public const COMMAND = 'console.command';
  27250. /**
  27251. @Event("Symfony\Component\Console\Event\ConsoleSignalEvent")
  27252. */
  27253. public const SIGNAL = 'console.signal';
  27254. /**
  27255. @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
  27256. */
  27257. public const TERMINATE = 'console.terminate';
  27258. /**
  27259. @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
  27260. */
  27261. public const ERROR = 'console.error';
  27262. public const ALIASES = [
  27263. ConsoleCommandEvent::class => self::COMMAND,
  27264. ConsoleErrorEvent::class => self::ERROR,
  27265. ConsoleSignalEvent::class => self::SIGNAL,
  27266. ConsoleTerminateEvent::class => self::TERMINATE,
  27267. ];
  27268. }
  27269. <?php
  27270. namespace Symfony\Component\Console;
  27271. use Symfony\Component\Console\Output\OutputInterface;
  27272. final class Cursor
  27273. {
  27274. private $output;
  27275. private $input;
  27276. public function __construct(OutputInterface $output, $input = null)
  27277. {
  27278. $this->output = $output;
  27279. $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+'));
  27280. }
  27281. public function moveUp(int $lines = 1): self
  27282. {
  27283. $this->output->write(sprintf("\x1b[%dA", $lines));
  27284. return $this;
  27285. }
  27286. public function moveDown(int $lines = 1): self
  27287. {
  27288. $this->output->write(sprintf("\x1b[%dB", $lines));
  27289. return $this;
  27290. }
  27291. public function moveRight(int $columns = 1): self
  27292. {
  27293. $this->output->write(sprintf("\x1b[%dC", $columns));
  27294. return $this;
  27295. }
  27296. public function moveLeft(int $columns = 1): self
  27297. {
  27298. $this->output->write(sprintf("\x1b[%dD", $columns));
  27299. return $this;
  27300. }
  27301. public function moveToColumn(int $column): self
  27302. {
  27303. $this->output->write(sprintf("\x1b[%dG", $column));
  27304. return $this;
  27305. }
  27306. public function moveToPosition(int $column, int $row): self
  27307. {
  27308. $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column));
  27309. return $this;
  27310. }
  27311. public function savePosition(): self
  27312. {
  27313. $this->output->write("\x1b7");
  27314. return $this;
  27315. }
  27316. public function restorePosition(): self
  27317. {
  27318. $this->output->write("\x1b8");
  27319. return $this;
  27320. }
  27321. public function hide(): self
  27322. {
  27323. $this->output->write("\x1b[?25l");
  27324. return $this;
  27325. }
  27326. public function show(): self
  27327. {
  27328. $this->output->write("\x1b[?25h\x1b[?0c");
  27329. return $this;
  27330. }
  27331. public function clearLine(): self
  27332. {
  27333. $this->output->write("\x1b[2K");
  27334. return $this;
  27335. }
  27336. public function clearLineAfter(): self
  27337. {
  27338. $this->output->write("\x1b[K");
  27339. return $this;
  27340. }
  27341. public function clearOutput(): self
  27342. {
  27343. $this->output->write("\x1b[0J");
  27344. return $this;
  27345. }
  27346. public function clearScreen(): self
  27347. {
  27348. $this->output->write("\x1b[2J");
  27349. return $this;
  27350. }
  27351. public function getCurrentPosition(): array
  27352. {
  27353. static $isTtySupported;
  27354. if (null === $isTtySupported && \function_exists('proc_open')) {
  27355. $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
  27356. }
  27357. if (!$isTtySupported) {
  27358. return [1, 1];
  27359. }
  27360. $sttyMode = shell_exec('stty -g');
  27361. shell_exec('stty -icanon -echo');
  27362. @fwrite($this->input, "\033[6n");
  27363. $code = trim(fread($this->input, 1024));
  27364. shell_exec(sprintf('stty %s', $sttyMode));
  27365. sscanf($code, "\033[%d;%dR", $row, $col);
  27366. return [$col, $row];
  27367. }
  27368. }
  27369. <?php
  27370. namespace Symfony\Component\Console;
  27371. use Symfony\Component\Console\Command\Command;
  27372. use Symfony\Component\Console\Command\CompleteCommand;
  27373. use Symfony\Component\Console\Command\DumpCompletionCommand;
  27374. use Symfony\Component\Console\Command\HelpCommand;
  27375. use Symfony\Component\Console\Command\LazyCommand;
  27376. use Symfony\Component\Console\Command\ListCommand;
  27377. use Symfony\Component\Console\Command\SignalableCommandInterface;
  27378. use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
  27379. use Symfony\Component\Console\Completion\CompletionInput;
  27380. use Symfony\Component\Console\Completion\CompletionSuggestions;
  27381. use Symfony\Component\Console\Event\ConsoleCommandEvent;
  27382. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  27383. use Symfony\Component\Console\Event\ConsoleSignalEvent;
  27384. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  27385. use Symfony\Component\Console\Exception\CommandNotFoundException;
  27386. use Symfony\Component\Console\Exception\ExceptionInterface;
  27387. use Symfony\Component\Console\Exception\LogicException;
  27388. use Symfony\Component\Console\Exception\NamespaceNotFoundException;
  27389. use Symfony\Component\Console\Exception\RuntimeException;
  27390. use Symfony\Component\Console\Formatter\OutputFormatter;
  27391. use Symfony\Component\Console\Helper\DebugFormatterHelper;
  27392. use Symfony\Component\Console\Helper\FormatterHelper;
  27393. use Symfony\Component\Console\Helper\Helper;
  27394. use Symfony\Component\Console\Helper\HelperSet;
  27395. use Symfony\Component\Console\Helper\ProcessHelper;
  27396. use Symfony\Component\Console\Helper\QuestionHelper;
  27397. use Symfony\Component\Console\Input\ArgvInput;
  27398. use Symfony\Component\Console\Input\ArrayInput;
  27399. use Symfony\Component\Console\Input\InputArgument;
  27400. use Symfony\Component\Console\Input\InputAwareInterface;
  27401. use Symfony\Component\Console\Input\InputDefinition;
  27402. use Symfony\Component\Console\Input\InputInterface;
  27403. use Symfony\Component\Console\Input\InputOption;
  27404. use Symfony\Component\Console\Output\ConsoleOutput;
  27405. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  27406. use Symfony\Component\Console\Output\OutputInterface;
  27407. use Symfony\Component\Console\SignalRegistry\SignalRegistry;
  27408. use Symfony\Component\Console\Style\SymfonyStyle;
  27409. use Symfony\Component\ErrorHandler\ErrorHandler;
  27410. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  27411. use Symfony\Contracts\Service\ResetInterface;
  27412. class Application implements ResetInterface
  27413. {
  27414. private $commands = [];
  27415. private $wantHelps = false;
  27416. private $runningCommand;
  27417. private $name;
  27418. private $version;
  27419. private $commandLoader;
  27420. private $catchExceptions = true;
  27421. private $autoExit = true;
  27422. private $definition;
  27423. private $helperSet;
  27424. private $dispatcher;
  27425. private $terminal;
  27426. private $defaultCommand;
  27427. private $singleCommand = false;
  27428. private $initialized;
  27429. private $signalRegistry;
  27430. private $signalsToDispatchEvent = [];
  27431. public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
  27432. {
  27433. $this->name = $name;
  27434. $this->version = $version;
  27435. $this->terminal = new Terminal();
  27436. $this->defaultCommand = 'list';
  27437. if (\defined('SIGINT') && SignalRegistry::isSupported()) {
  27438. $this->signalRegistry = new SignalRegistry();
  27439. $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2];
  27440. }
  27441. }
  27442. public function setDispatcher(EventDispatcherInterface $dispatcher)
  27443. {
  27444. $this->dispatcher = $dispatcher;
  27445. }
  27446. public function setCommandLoader(CommandLoaderInterface $commandLoader)
  27447. {
  27448. $this->commandLoader = $commandLoader;
  27449. }
  27450. public function getSignalRegistry(): SignalRegistry
  27451. {
  27452. if (!$this->signalRegistry) {
  27453. throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
  27454. }
  27455. return $this->signalRegistry;
  27456. }
  27457. public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
  27458. {
  27459. $this->signalsToDispatchEvent = $signalsToDispatchEvent;
  27460. }
  27461. public function run(?InputInterface $input = null, ?OutputInterface $output = null)
  27462. {
  27463. if (\function_exists('putenv')) {
  27464. @putenv('LINES='.$this->terminal->getHeight());
  27465. @putenv('COLUMNS='.$this->terminal->getWidth());
  27466. }
  27467. if (null === $input) {
  27468. $input = new ArgvInput();
  27469. }
  27470. if (null === $output) {
  27471. $output = new ConsoleOutput();
  27472. }
  27473. $renderException = function (\Throwable $e) use ($output) {
  27474. if ($output instanceof ConsoleOutputInterface) {
  27475. $this->renderThrowable($e, $output->getErrorOutput());
  27476. } else {
  27477. $this->renderThrowable($e, $output);
  27478. }
  27479. };
  27480. if ($phpHandler = set_exception_handler($renderException)) {
  27481. restore_exception_handler();
  27482. if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
  27483. $errorHandler = true;
  27484. } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
  27485. $phpHandler[0]->setExceptionHandler($errorHandler);
  27486. }
  27487. }
  27488. try {
  27489. $this->configureIO($input, $output);
  27490. $exitCode = $this->doRun($input, $output);
  27491. } catch (\Exception $e) {
  27492. if (!$this->catchExceptions) {
  27493. throw $e;
  27494. }
  27495. $renderException($e);
  27496. $exitCode = $e->getCode();
  27497. if (is_numeric($exitCode)) {
  27498. $exitCode = (int) $exitCode;
  27499. if ($exitCode <= 0) {
  27500. $exitCode = 1;
  27501. }
  27502. } else {
  27503. $exitCode = 1;
  27504. }
  27505. } finally {
  27506. if (!$phpHandler) {
  27507. if (set_exception_handler($renderException) === $renderException) {
  27508. restore_exception_handler();
  27509. }
  27510. restore_exception_handler();
  27511. } elseif (!$errorHandler) {
  27512. $finalHandler = $phpHandler[0]->setExceptionHandler(null);
  27513. if ($finalHandler !== $renderException) {
  27514. $phpHandler[0]->setExceptionHandler($finalHandler);
  27515. }
  27516. }
  27517. }
  27518. if ($this->autoExit) {
  27519. if ($exitCode > 255) {
  27520. $exitCode = 255;
  27521. }
  27522. exit($exitCode);
  27523. }
  27524. return $exitCode;
  27525. }
  27526. public function doRun(InputInterface $input, OutputInterface $output)
  27527. {
  27528. if (true === $input->hasParameterOption(['--version', '-V'], true)) {
  27529. $output->writeln($this->getLongVersion());
  27530. return 0;
  27531. }
  27532. try {
  27533. $input->bind($this->getDefinition());
  27534. } catch (ExceptionInterface $e) {
  27535. }
  27536. $name = $this->getCommandName($input);
  27537. if (true === $input->hasParameterOption(['--help', '-h'], true)) {
  27538. if (!$name) {
  27539. $name = 'help';
  27540. $input = new ArrayInput(['command_name' => $this->defaultCommand]);
  27541. } else {
  27542. $this->wantHelps = true;
  27543. }
  27544. }
  27545. if (!$name) {
  27546. $name = $this->defaultCommand;
  27547. $definition = $this->getDefinition();
  27548. $definition->setArguments(array_merge(
  27549. $definition->getArguments(),
  27550. [
  27551. 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
  27552. ]
  27553. ));
  27554. }
  27555. try {
  27556. $this->runningCommand = null;
  27557. $command = $this->find($name);
  27558. } catch (\Throwable $e) {
  27559. if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
  27560. if (null !== $this->dispatcher) {
  27561. $event = new ConsoleErrorEvent($input, $output, $e);
  27562. $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
  27563. if (0 === $event->getExitCode()) {
  27564. return 0;
  27565. }
  27566. $e = $event->getError();
  27567. }
  27568. throw $e;
  27569. }
  27570. $alternative = $alternatives[0];
  27571. $style = new SymfonyStyle($input, $output);
  27572. $output->writeln('');
  27573. $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true);
  27574. $output->writeln($formattedBlock);
  27575. if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) {
  27576. if (null !== $this->dispatcher) {
  27577. $event = new ConsoleErrorEvent($input, $output, $e);
  27578. $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
  27579. return $event->getExitCode();
  27580. }
  27581. return 1;
  27582. }
  27583. $command = $this->find($alternative);
  27584. }
  27585. if ($command instanceof LazyCommand) {
  27586. $command = $command->getCommand();
  27587. }
  27588. $this->runningCommand = $command;
  27589. $exitCode = $this->doRunCommand($command, $input, $output);
  27590. $this->runningCommand = null;
  27591. return $exitCode;
  27592. }
  27593. public function reset()
  27594. {
  27595. }
  27596. public function setHelperSet(HelperSet $helperSet)
  27597. {
  27598. $this->helperSet = $helperSet;
  27599. }
  27600. public function getHelperSet()
  27601. {
  27602. if (!$this->helperSet) {
  27603. $this->helperSet = $this->getDefaultHelperSet();
  27604. }
  27605. return $this->helperSet;
  27606. }
  27607. public function setDefinition(InputDefinition $definition)
  27608. {
  27609. $this->definition = $definition;
  27610. }
  27611. public function getDefinition()
  27612. {
  27613. if (!$this->definition) {
  27614. $this->definition = $this->getDefaultInputDefinition();
  27615. }
  27616. if ($this->singleCommand) {
  27617. $inputDefinition = $this->definition;
  27618. $inputDefinition->setArguments();
  27619. return $inputDefinition;
  27620. }
  27621. return $this->definition;
  27622. }
  27623. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  27624. {
  27625. if (
  27626. CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType()
  27627. && 'command' === $input->getCompletionName()
  27628. ) {
  27629. $commandNames = [];
  27630. foreach ($this->all() as $name => $command) {
  27631. if ($command->isHidden() || $command->getName() !== $name) {
  27632. continue;
  27633. }
  27634. $commandNames[] = $command->getName();
  27635. foreach ($command->getAliases() as $name) {
  27636. $commandNames[] = $name;
  27637. }
  27638. }
  27639. $suggestions->suggestValues(array_filter($commandNames));
  27640. return;
  27641. }
  27642. if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) {
  27643. $suggestions->suggestOptions($this->getDefinition()->getOptions());
  27644. return;
  27645. }
  27646. }
  27647. public function getHelp()
  27648. {
  27649. return $this->getLongVersion();
  27650. }
  27651. public function areExceptionsCaught()
  27652. {
  27653. return $this->catchExceptions;
  27654. }
  27655. public function setCatchExceptions(bool $boolean)
  27656. {
  27657. $this->catchExceptions = $boolean;
  27658. }
  27659. public function isAutoExitEnabled()
  27660. {
  27661. return $this->autoExit;
  27662. }
  27663. public function setAutoExit(bool $boolean)
  27664. {
  27665. $this->autoExit = $boolean;
  27666. }
  27667. public function getName()
  27668. {
  27669. return $this->name;
  27670. }
  27671. public function setName(string $name)
  27672. {
  27673. $this->name = $name;
  27674. }
  27675. public function getVersion()
  27676. {
  27677. return $this->version;
  27678. }
  27679. public function setVersion(string $version)
  27680. {
  27681. $this->version = $version;
  27682. }
  27683. public function getLongVersion()
  27684. {
  27685. if ('UNKNOWN' !== $this->getName()) {
  27686. if ('UNKNOWN' !== $this->getVersion()) {
  27687. return sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());
  27688. }
  27689. return $this->getName();
  27690. }
  27691. return 'Console Tool';
  27692. }
  27693. public function register(string $name)
  27694. {
  27695. return $this->add(new Command($name));
  27696. }
  27697. public function addCommands(array $commands)
  27698. {
  27699. foreach ($commands as $command) {
  27700. $this->add($command);
  27701. }
  27702. }
  27703. public function add(Command $command)
  27704. {
  27705. $this->init();
  27706. $command->setApplication($this);
  27707. if (!$command->isEnabled()) {
  27708. $command->setApplication(null);
  27709. return null;
  27710. }
  27711. if (!$command instanceof LazyCommand) {
  27712. $command->getDefinition();
  27713. }
  27714. if (!$command->getName()) {
  27715. throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command)));
  27716. }
  27717. $this->commands[$command->getName()] = $command;
  27718. foreach ($command->getAliases() as $alias) {
  27719. $this->commands[$alias] = $command;
  27720. }
  27721. return $command;
  27722. }
  27723. public function get(string $name)
  27724. {
  27725. $this->init();
  27726. if (!$this->has($name)) {
  27727. throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
  27728. }
  27729. if (!isset($this->commands[$name])) {
  27730. throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
  27731. }
  27732. $command = $this->commands[$name];
  27733. if ($this->wantHelps) {
  27734. $this->wantHelps = false;
  27735. $helpCommand = $this->get('help');
  27736. $helpCommand->setCommand($command);
  27737. return $helpCommand;
  27738. }
  27739. return $command;
  27740. }
  27741. public function has(string $name)
  27742. {
  27743. $this->init();
  27744. return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));
  27745. }
  27746. public function getNamespaces()
  27747. {
  27748. $namespaces = [];
  27749. foreach ($this->all() as $command) {
  27750. if ($command->isHidden()) {
  27751. continue;
  27752. }
  27753. $namespaces[] = $this->extractAllNamespaces($command->getName());
  27754. foreach ($command->getAliases() as $alias) {
  27755. $namespaces[] = $this->extractAllNamespaces($alias);
  27756. }
  27757. }
  27758. return array_values(array_unique(array_filter(array_merge([], ...$namespaces))));
  27759. }
  27760. public function findNamespace(string $namespace)
  27761. {
  27762. $allNamespaces = $this->getNamespaces();
  27763. $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*';
  27764. $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
  27765. if (empty($namespaces)) {
  27766. $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
  27767. if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
  27768. if (1 == \count($alternatives)) {
  27769. $message .= "\n\nDid you mean this?\n ";
  27770. } else {
  27771. $message .= "\n\nDid you mean one of these?\n ";
  27772. }
  27773. $message .= implode("\n ", $alternatives);
  27774. }
  27775. throw new NamespaceNotFoundException($message, $alternatives);
  27776. }
  27777. $exact = \in_array($namespace, $namespaces, true);
  27778. if (\count($namespaces) > 1 && !$exact) {
  27779. throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
  27780. }
  27781. return $exact ? $namespace : reset($namespaces);
  27782. }
  27783. public function find(string $name)
  27784. {
  27785. $this->init();
  27786. $aliases = [];
  27787. foreach ($this->commands as $command) {
  27788. foreach ($command->getAliases() as $alias) {
  27789. if (!$this->has($alias)) {
  27790. $this->commands[$alias] = $command;
  27791. }
  27792. }
  27793. }
  27794. if ($this->has($name)) {
  27795. return $this->get($name);
  27796. }
  27797. $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
  27798. $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*';
  27799. $commands = preg_grep('{^'.$expr.'}', $allCommands);
  27800. if (empty($commands)) {
  27801. $commands = preg_grep('{^'.$expr.'}i', $allCommands);
  27802. }
  27803. if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
  27804. if (false !== $pos = strrpos($name, ':')) {
  27805. $this->findNamespace(substr($name, 0, $pos));
  27806. }
  27807. $message = sprintf('Command "%s" is not defined.', $name);
  27808. if ($alternatives = $this->findAlternatives($name, $allCommands)) {
  27809. $alternatives = array_filter($alternatives, function ($name) {
  27810. return !$this->get($name)->isHidden();
  27811. });
  27812. if (1 == \count($alternatives)) {
  27813. $message .= "\n\nDid you mean this?\n ";
  27814. } else {
  27815. $message .= "\n\nDid you mean one of these?\n ";
  27816. }
  27817. $message .= implode("\n ", $alternatives);
  27818. }
  27819. throw new CommandNotFoundException($message, array_values($alternatives));
  27820. }
  27821. if (\count($commands) > 1) {
  27822. $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
  27823. $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
  27824. if (!$commandList[$nameOrAlias] instanceof Command) {
  27825. $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
  27826. }
  27827. $commandName = $commandList[$nameOrAlias]->getName();
  27828. $aliases[$nameOrAlias] = $commandName;
  27829. return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
  27830. }));
  27831. }
  27832. if (\count($commands) > 1) {
  27833. $usableWidth = $this->terminal->getWidth() - 10;
  27834. $abbrevs = array_values($commands);
  27835. $maxLen = 0;
  27836. foreach ($abbrevs as $abbrev) {
  27837. $maxLen = max(Helper::width($abbrev), $maxLen);
  27838. }
  27839. $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) {
  27840. if ($commandList[$cmd]->isHidden()) {
  27841. unset($commands[array_search($cmd, $commands)]);
  27842. return false;
  27843. }
  27844. $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
  27845. return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
  27846. }, array_values($commands));
  27847. if (\count($commands) > 1) {
  27848. $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));
  27849. throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands));
  27850. }
  27851. }
  27852. $command = $this->get(reset($commands));
  27853. if ($command->isHidden()) {
  27854. throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
  27855. }
  27856. return $command;
  27857. }
  27858. public function all(?string $namespace = null)
  27859. {
  27860. $this->init();
  27861. if (null === $namespace) {
  27862. if (!$this->commandLoader) {
  27863. return $this->commands;
  27864. }
  27865. $commands = $this->commands;
  27866. foreach ($this->commandLoader->getNames() as $name) {
  27867. if (!isset($commands[$name]) && $this->has($name)) {
  27868. $commands[$name] = $this->get($name);
  27869. }
  27870. }
  27871. return $commands;
  27872. }
  27873. $commands = [];
  27874. foreach ($this->commands as $name => $command) {
  27875. if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
  27876. $commands[$name] = $command;
  27877. }
  27878. }
  27879. if ($this->commandLoader) {
  27880. foreach ($this->commandLoader->getNames() as $name) {
  27881. if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) {
  27882. $commands[$name] = $this->get($name);
  27883. }
  27884. }
  27885. }
  27886. return $commands;
  27887. }
  27888. public static function getAbbreviations(array $names)
  27889. {
  27890. $abbrevs = [];
  27891. foreach ($names as $name) {
  27892. for ($len = \strlen($name); $len > 0; --$len) {
  27893. $abbrev = substr($name, 0, $len);
  27894. $abbrevs[$abbrev][] = $name;
  27895. }
  27896. }
  27897. return $abbrevs;
  27898. }
  27899. public function renderThrowable(\Throwable $e, OutputInterface $output): void
  27900. {
  27901. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  27902. $this->doRenderThrowable($e, $output);
  27903. if (null !== $this->runningCommand) {
  27904. $output->writeln(sprintf('<info>%s</info>', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
  27905. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  27906. }
  27907. }
  27908. protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void
  27909. {
  27910. do {
  27911. $message = trim($e->getMessage());
  27912. if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  27913. $class = get_debug_type($e);
  27914. $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
  27915. $len = Helper::width($title);
  27916. } else {
  27917. $len = 0;
  27918. }
  27919. if (str_contains($message, "@anonymous\0")) {
  27920. $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', function ($m) {
  27921. return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
  27922. }, $message);
  27923. }
  27924. $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
  27925. $lines = [];
  27926. foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) {
  27927. foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
  27928. $lineLength = Helper::width($line) + 4;
  27929. $lines[] = [$line, $lineLength];
  27930. $len = max($lineLength, $len);
  27931. }
  27932. }
  27933. $messages = [];
  27934. if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  27935. $messages[] = sprintf('<comment>%s</comment>', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
  27936. }
  27937. $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));
  27938. if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  27939. $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::width($title))));
  27940. }
  27941. foreach ($lines as $line) {
  27942. $messages[] = sprintf('<error> %s %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
  27943. }
  27944. $messages[] = $emptyLine;
  27945. $messages[] = '';
  27946. $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
  27947. if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
  27948. $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
  27949. $trace = $e->getTrace();
  27950. array_unshift($trace, [
  27951. 'function' => '',
  27952. 'file' => $e->getFile() ?: 'n/a',
  27953. 'line' => $e->getLine() ?: 'n/a',
  27954. 'args' => [],
  27955. ]);
  27956. for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
  27957. $class = $trace[$i]['class'] ?? '';
  27958. $type = $trace[$i]['type'] ?? '';
  27959. $function = $trace[$i]['function'] ?? '';
  27960. $file = $trace[$i]['file'] ?? 'n/a';
  27961. $line = $trace[$i]['line'] ?? 'n/a';
  27962. $output->writeln(sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
  27963. }
  27964. $output->writeln('', OutputInterface::VERBOSITY_QUIET);
  27965. }
  27966. } while ($e = $e->getPrevious());
  27967. }
  27968. protected function configureIO(InputInterface $input, OutputInterface $output)
  27969. {
  27970. if (true === $input->hasParameterOption(['--ansi'], true)) {
  27971. $output->setDecorated(true);
  27972. } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {
  27973. $output->setDecorated(false);
  27974. }
  27975. if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {
  27976. $input->setInteractive(false);
  27977. }
  27978. switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
  27979. case -1:
  27980. $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
  27981. break;
  27982. case 1:
  27983. $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
  27984. break;
  27985. case 2:
  27986. $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
  27987. break;
  27988. case 3:
  27989. $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
  27990. break;
  27991. default:
  27992. $shellVerbosity = 0;
  27993. break;
  27994. }
  27995. if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
  27996. $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
  27997. $shellVerbosity = -1;
  27998. } else {
  27999. if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {
  28000. $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
  28001. $shellVerbosity = 3;
  28002. } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {
  28003. $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
  28004. $shellVerbosity = 2;
  28005. } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {
  28006. $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
  28007. $shellVerbosity = 1;
  28008. }
  28009. }
  28010. if (-1 === $shellVerbosity) {
  28011. $input->setInteractive(false);
  28012. }
  28013. if (\function_exists('putenv')) {
  28014. @putenv('SHELL_VERBOSITY='.$shellVerbosity);
  28015. }
  28016. $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
  28017. $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
  28018. }
  28019. protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
  28020. {
  28021. foreach ($command->getHelperSet() as $helper) {
  28022. if ($helper instanceof InputAwareInterface) {
  28023. $helper->setInput($input);
  28024. }
  28025. }
  28026. if ($this->signalsToDispatchEvent) {
  28027. $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
  28028. if ($commandSignals || null !== $this->dispatcher) {
  28029. if (!$this->signalRegistry) {
  28030. throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
  28031. }
  28032. if (Terminal::hasSttyAvailable()) {
  28033. $sttyMode = shell_exec('stty -g');
  28034. foreach ([\SIGINT, \SIGTERM] as $signal) {
  28035. $this->signalRegistry->register($signal, static function () use ($sttyMode) {
  28036. shell_exec('stty '.$sttyMode);
  28037. });
  28038. }
  28039. }
  28040. }
  28041. if (null !== $this->dispatcher) {
  28042. foreach ($this->signalsToDispatchEvent as $signal) {
  28043. $event = new ConsoleSignalEvent($command, $input, $output, $signal);
  28044. $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
  28045. $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
  28046. if (!$hasNext) {
  28047. if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
  28048. exit(0);
  28049. }
  28050. }
  28051. });
  28052. }
  28053. }
  28054. foreach ($commandSignals as $signal) {
  28055. $this->signalRegistry->register($signal, [$command, 'handleSignal']);
  28056. }
  28057. }
  28058. if (null === $this->dispatcher) {
  28059. return $command->run($input, $output);
  28060. }
  28061. try {
  28062. $command->mergeApplicationDefinition();
  28063. $input->bind($command->getDefinition());
  28064. } catch (ExceptionInterface $e) {
  28065. }
  28066. $event = new ConsoleCommandEvent($command, $input, $output);
  28067. $e = null;
  28068. try {
  28069. $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
  28070. if ($event->commandShouldRun()) {
  28071. $exitCode = $command->run($input, $output);
  28072. } else {
  28073. $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
  28074. }
  28075. } catch (\Throwable $e) {
  28076. $event = new ConsoleErrorEvent($input, $output, $e, $command);
  28077. $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
  28078. $e = $event->getError();
  28079. if (0 === $exitCode = $event->getExitCode()) {
  28080. $e = null;
  28081. }
  28082. }
  28083. $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
  28084. $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
  28085. if (null !== $e) {
  28086. throw $e;
  28087. }
  28088. return $event->getExitCode();
  28089. }
  28090. protected function getCommandName(InputInterface $input)
  28091. {
  28092. return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
  28093. }
  28094. protected function getDefaultInputDefinition()
  28095. {
  28096. return new InputDefinition([
  28097. new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
  28098. new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the <info>'.$this->defaultCommand.'</info> command'),
  28099. new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
  28100. new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
  28101. new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
  28102. new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null),
  28103. new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
  28104. ]);
  28105. }
  28106. protected function getDefaultCommands()
  28107. {
  28108. return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()];
  28109. }
  28110. protected function getDefaultHelperSet()
  28111. {
  28112. return new HelperSet([
  28113. new FormatterHelper(),
  28114. new DebugFormatterHelper(),
  28115. new ProcessHelper(),
  28116. new QuestionHelper(),
  28117. ]);
  28118. }
  28119. private function getAbbreviationSuggestions(array $abbrevs): string
  28120. {
  28121. return ' '.implode("\n ", $abbrevs);
  28122. }
  28123. public function extractNamespace(string $name, ?int $limit = null)
  28124. {
  28125. $parts = explode(':', $name, -1);
  28126. return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
  28127. }
  28128. private function findAlternatives(string $name, iterable $collection): array
  28129. {
  28130. $threshold = 1e3;
  28131. $alternatives = [];
  28132. $collectionParts = [];
  28133. foreach ($collection as $item) {
  28134. $collectionParts[$item] = explode(':', $item);
  28135. }
  28136. foreach (explode(':', $name) as $i => $subname) {
  28137. foreach ($collectionParts as $collectionName => $parts) {
  28138. $exists = isset($alternatives[$collectionName]);
  28139. if (!isset($parts[$i]) && $exists) {
  28140. $alternatives[$collectionName] += $threshold;
  28141. continue;
  28142. } elseif (!isset($parts[$i])) {
  28143. continue;
  28144. }
  28145. $lev = levenshtein($subname, $parts[$i]);
  28146. if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {
  28147. $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
  28148. } elseif ($exists) {
  28149. $alternatives[$collectionName] += $threshold;
  28150. }
  28151. }
  28152. }
  28153. foreach ($collection as $item) {
  28154. $lev = levenshtein($name, $item);
  28155. if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
  28156. $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
  28157. }
  28158. }
  28159. $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
  28160. ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
  28161. return array_keys($alternatives);
  28162. }
  28163. public function setDefaultCommand(string $commandName, bool $isSingleCommand = false)
  28164. {
  28165. $this->defaultCommand = explode('|', ltrim($commandName, '|'))[0];
  28166. if ($isSingleCommand) {
  28167. $this->find($commandName);
  28168. $this->singleCommand = true;
  28169. }
  28170. return $this;
  28171. }
  28172. public function isSingleCommand(): bool
  28173. {
  28174. return $this->singleCommand;
  28175. }
  28176. private function splitStringByWidth(string $string, int $width): array
  28177. {
  28178. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  28179. return str_split($string, $width);
  28180. }
  28181. $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
  28182. $lines = [];
  28183. $line = '';
  28184. $offset = 0;
  28185. while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
  28186. $offset += \strlen($m[0]);
  28187. foreach (preg_split('//u', $m[0]) as $char) {
  28188. if (mb_strwidth($line.$char, 'utf8') <= $width) {
  28189. $line .= $char;
  28190. continue;
  28191. }
  28192. $lines[] = str_pad($line, $width);
  28193. $line = $char;
  28194. }
  28195. }
  28196. $lines[] = \count($lines) ? str_pad($line, $width) : $line;
  28197. mb_convert_variables($encoding, 'utf8', $lines);
  28198. return $lines;
  28199. }
  28200. private function extractAllNamespaces(string $name): array
  28201. {
  28202. $parts = explode(':', $name, -1);
  28203. $namespaces = [];
  28204. foreach ($parts as $part) {
  28205. if (\count($namespaces)) {
  28206. $namespaces[] = end($namespaces).':'.$part;
  28207. } else {
  28208. $namespaces[] = $part;
  28209. }
  28210. }
  28211. return $namespaces;
  28212. }
  28213. private function init()
  28214. {
  28215. if ($this->initialized) {
  28216. return;
  28217. }
  28218. $this->initialized = true;
  28219. foreach ($this->getDefaultCommands() as $command) {
  28220. $this->add($command);
  28221. }
  28222. }
  28223. }
  28224. <?php
  28225. namespace Symfony\Component\Console\Logger;
  28226. use Psr\Log\AbstractLogger;
  28227. use Psr\Log\InvalidArgumentException;
  28228. use Psr\Log\LogLevel;
  28229. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  28230. use Symfony\Component\Console\Output\OutputInterface;
  28231. class ConsoleLogger extends AbstractLogger
  28232. {
  28233. public const INFO = 'info';
  28234. public const ERROR = 'error';
  28235. private $output;
  28236. private $verbosityLevelMap = [
  28237. LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
  28238. LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
  28239. LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
  28240. LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
  28241. LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
  28242. LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
  28243. LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
  28244. LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
  28245. ];
  28246. private $formatLevelMap = [
  28247. LogLevel::EMERGENCY => self::ERROR,
  28248. LogLevel::ALERT => self::ERROR,
  28249. LogLevel::CRITICAL => self::ERROR,
  28250. LogLevel::ERROR => self::ERROR,
  28251. LogLevel::WARNING => self::INFO,
  28252. LogLevel::NOTICE => self::INFO,
  28253. LogLevel::INFO => self::INFO,
  28254. LogLevel::DEBUG => self::INFO,
  28255. ];
  28256. private $errored = false;
  28257. public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
  28258. {
  28259. $this->output = $output;
  28260. $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
  28261. $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
  28262. }
  28263. public function log($level, $message, array $context = [])
  28264. {
  28265. if (!isset($this->verbosityLevelMap[$level])) {
  28266. throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
  28267. }
  28268. $output = $this->output;
  28269. if (self::ERROR === $this->formatLevelMap[$level]) {
  28270. if ($this->output instanceof ConsoleOutputInterface) {
  28271. $output = $output->getErrorOutput();
  28272. }
  28273. $this->errored = true;
  28274. }
  28275. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
  28276. $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
  28277. }
  28278. }
  28279. public function hasErrored()
  28280. {
  28281. return $this->errored;
  28282. }
  28283. private function interpolate(string $message, array $context): string
  28284. {
  28285. if (!str_contains($message, '{')) {
  28286. return $message;
  28287. }
  28288. $replacements = [];
  28289. foreach ($context as $key => $val) {
  28290. if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
  28291. $replacements["{{$key}}"] = $val;
  28292. } elseif ($val instanceof \DateTimeInterface) {
  28293. $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
  28294. } elseif (\is_object($val)) {
  28295. $replacements["{{$key}}"] = '[object '.\get_class($val).']';
  28296. } else {
  28297. $replacements["{{$key}}"] = '['.\gettype($val).']';
  28298. }
  28299. }
  28300. return strtr($message, $replacements);
  28301. }
  28302. }
  28303. <?php
  28304. namespace Symfony\Component\Console\Attribute;
  28305. #[\Attribute(\Attribute::TARGET_CLASS)]
  28306. class AsCommand
  28307. {
  28308. public function __construct(
  28309. public string $name,
  28310. public ?string $description = null,
  28311. array $aliases = [],
  28312. bool $hidden = false,
  28313. ) {
  28314. if (!$hidden && !$aliases) {
  28315. return;
  28316. }
  28317. $name = explode('|', $name);
  28318. $name = array_merge($name, $aliases);
  28319. if ($hidden && '' !== $name[0]) {
  28320. array_unshift($name, '');
  28321. }
  28322. $this->name = implode('|', $name);
  28323. }
  28324. }
  28325. <?php
  28326. namespace Symfony\Component\Console\Input;
  28327. interface StreamableInputInterface extends InputInterface
  28328. {
  28329. public function setStream($stream);
  28330. public function getStream();
  28331. }
  28332. <?php
  28333. namespace Symfony\Component\Console\Input;
  28334. use Symfony\Component\Console\Exception\InvalidArgumentException;
  28335. use Symfony\Component\Console\Exception\InvalidOptionException;
  28336. class ArrayInput extends Input
  28337. {
  28338. private $parameters;
  28339. public function __construct(array $parameters, ?InputDefinition $definition = null)
  28340. {
  28341. $this->parameters = $parameters;
  28342. parent::__construct($definition);
  28343. }
  28344. public function getFirstArgument()
  28345. {
  28346. foreach ($this->parameters as $param => $value) {
  28347. if ($param && \is_string($param) && '-' === $param[0]) {
  28348. continue;
  28349. }
  28350. return $value;
  28351. }
  28352. return null;
  28353. }
  28354. public function hasParameterOption($values, bool $onlyParams = false)
  28355. {
  28356. $values = (array) $values;
  28357. foreach ($this->parameters as $k => $v) {
  28358. if (!\is_int($k)) {
  28359. $v = $k;
  28360. }
  28361. if ($onlyParams && '--' === $v) {
  28362. return false;
  28363. }
  28364. if (\in_array($v, $values)) {
  28365. return true;
  28366. }
  28367. }
  28368. return false;
  28369. }
  28370. public function getParameterOption($values, $default = false, bool $onlyParams = false)
  28371. {
  28372. $values = (array) $values;
  28373. foreach ($this->parameters as $k => $v) {
  28374. if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) {
  28375. return $default;
  28376. }
  28377. if (\is_int($k)) {
  28378. if (\in_array($v, $values)) {
  28379. return true;
  28380. }
  28381. } elseif (\in_array($k, $values)) {
  28382. return $v;
  28383. }
  28384. }
  28385. return $default;
  28386. }
  28387. public function __toString()
  28388. {
  28389. $params = [];
  28390. foreach ($this->parameters as $param => $val) {
  28391. if ($param && \is_string($param) && '-' === $param[0]) {
  28392. $glue = ('-' === $param[1]) ? '=' : ' ';
  28393. if (\is_array($val)) {
  28394. foreach ($val as $v) {
  28395. $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
  28396. }
  28397. } else {
  28398. $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
  28399. }
  28400. } else {
  28401. $params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
  28402. }
  28403. }
  28404. return implode(' ', $params);
  28405. }
  28406. protected function parse()
  28407. {
  28408. foreach ($this->parameters as $key => $value) {
  28409. if ('--' === $key) {
  28410. return;
  28411. }
  28412. if (str_starts_with($key, '--')) {
  28413. $this->addLongOption(substr($key, 2), $value);
  28414. } elseif (str_starts_with($key, '-')) {
  28415. $this->addShortOption(substr($key, 1), $value);
  28416. } else {
  28417. $this->addArgument($key, $value);
  28418. }
  28419. }
  28420. }
  28421. private function addShortOption(string $shortcut, $value)
  28422. {
  28423. if (!$this->definition->hasShortcut($shortcut)) {
  28424. throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
  28425. }
  28426. $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
  28427. }
  28428. private function addLongOption(string $name, $value)
  28429. {
  28430. if (!$this->definition->hasOption($name)) {
  28431. if (!$this->definition->hasNegation($name)) {
  28432. throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
  28433. }
  28434. $optionName = $this->definition->negationToName($name);
  28435. $this->options[$optionName] = false;
  28436. return;
  28437. }
  28438. $option = $this->definition->getOption($name);
  28439. if (null === $value) {
  28440. if ($option->isValueRequired()) {
  28441. throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
  28442. }
  28443. if (!$option->isValueOptional()) {
  28444. $value = true;
  28445. }
  28446. }
  28447. $this->options[$name] = $value;
  28448. }
  28449. private function addArgument($name, $value)
  28450. {
  28451. if (!$this->definition->hasArgument($name)) {
  28452. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  28453. }
  28454. $this->arguments[$name] = $value;
  28455. }
  28456. }
  28457. <?php
  28458. namespace Symfony\Component\Console\Input;
  28459. use Symfony\Component\Console\Exception\RuntimeException;
  28460. class ArgvInput extends Input
  28461. {
  28462. private $tokens;
  28463. private $parsed;
  28464. public function __construct(?array $argv = null, ?InputDefinition $definition = null)
  28465. {
  28466. $argv = $argv ?? $_SERVER['argv'] ?? [];
  28467. array_shift($argv);
  28468. $this->tokens = $argv;
  28469. parent::__construct($definition);
  28470. }
  28471. protected function setTokens(array $tokens)
  28472. {
  28473. $this->tokens = $tokens;
  28474. }
  28475. protected function parse()
  28476. {
  28477. $parseOptions = true;
  28478. $this->parsed = $this->tokens;
  28479. while (null !== $token = array_shift($this->parsed)) {
  28480. $parseOptions = $this->parseToken($token, $parseOptions);
  28481. }
  28482. }
  28483. protected function parseToken(string $token, bool $parseOptions): bool
  28484. {
  28485. if ($parseOptions && '' == $token) {
  28486. $this->parseArgument($token);
  28487. } elseif ($parseOptions && '--' == $token) {
  28488. return false;
  28489. } elseif ($parseOptions && str_starts_with($token, '--')) {
  28490. $this->parseLongOption($token);
  28491. } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
  28492. $this->parseShortOption($token);
  28493. } else {
  28494. $this->parseArgument($token);
  28495. }
  28496. return $parseOptions;
  28497. }
  28498. private function parseShortOption(string $token)
  28499. {
  28500. $name = substr($token, 1);
  28501. if (\strlen($name) > 1) {
  28502. if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
  28503. $this->addShortOption($name[0], substr($name, 1));
  28504. } else {
  28505. $this->parseShortOptionSet($name);
  28506. }
  28507. } else {
  28508. $this->addShortOption($name, null);
  28509. }
  28510. }
  28511. private function parseShortOptionSet(string $name)
  28512. {
  28513. $len = \strlen($name);
  28514. for ($i = 0; $i < $len; ++$i) {
  28515. if (!$this->definition->hasShortcut($name[$i])) {
  28516. $encoding = mb_detect_encoding($name, null, true);
  28517. throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
  28518. }
  28519. $option = $this->definition->getOptionForShortcut($name[$i]);
  28520. if ($option->acceptValue()) {
  28521. $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
  28522. break;
  28523. } else {
  28524. $this->addLongOption($option->getName(), null);
  28525. }
  28526. }
  28527. }
  28528. private function parseLongOption(string $token)
  28529. {
  28530. $name = substr($token, 2);
  28531. if (false !== $pos = strpos($name, '=')) {
  28532. if ('' === $value = substr($name, $pos + 1)) {
  28533. array_unshift($this->parsed, $value);
  28534. }
  28535. $this->addLongOption(substr($name, 0, $pos), $value);
  28536. } else {
  28537. $this->addLongOption($name, null);
  28538. }
  28539. }
  28540. private function parseArgument(string $token)
  28541. {
  28542. $c = \count($this->arguments);
  28543. if ($this->definition->hasArgument($c)) {
  28544. $arg = $this->definition->getArgument($c);
  28545. $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
  28546. } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
  28547. $arg = $this->definition->getArgument($c - 1);
  28548. $this->arguments[$arg->getName()][] = $token;
  28549. } else {
  28550. $all = $this->definition->getArguments();
  28551. $symfonyCommandName = null;
  28552. if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) {
  28553. $symfonyCommandName = $this->arguments['command'] ?? null;
  28554. unset($all[$key]);
  28555. }
  28556. if (\count($all)) {
  28557. if ($symfonyCommandName) {
  28558. $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all)));
  28559. } else {
  28560. $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all)));
  28561. }
  28562. } elseif ($symfonyCommandName) {
  28563. $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token);
  28564. } else {
  28565. $message = sprintf('No arguments expected, got "%s".', $token);
  28566. }
  28567. throw new RuntimeException($message);
  28568. }
  28569. }
  28570. private function addShortOption(string $shortcut, $value)
  28571. {
  28572. if (!$this->definition->hasShortcut($shortcut)) {
  28573. throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
  28574. }
  28575. $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
  28576. }
  28577. private function addLongOption(string $name, $value)
  28578. {
  28579. if (!$this->definition->hasOption($name)) {
  28580. if (!$this->definition->hasNegation($name)) {
  28581. throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
  28582. }
  28583. $optionName = $this->definition->negationToName($name);
  28584. if (null !== $value) {
  28585. throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
  28586. }
  28587. $this->options[$optionName] = false;
  28588. return;
  28589. }
  28590. $option = $this->definition->getOption($name);
  28591. if (null !== $value && !$option->acceptValue()) {
  28592. throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
  28593. }
  28594. if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {
  28595. $next = array_shift($this->parsed);
  28596. if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
  28597. $value = $next;
  28598. } else {
  28599. array_unshift($this->parsed, $next);
  28600. }
  28601. }
  28602. if (null === $value) {
  28603. if ($option->isValueRequired()) {
  28604. throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
  28605. }
  28606. if (!$option->isArray() && !$option->isValueOptional()) {
  28607. $value = true;
  28608. }
  28609. }
  28610. if ($option->isArray()) {
  28611. $this->options[$name][] = $value;
  28612. } else {
  28613. $this->options[$name] = $value;
  28614. }
  28615. }
  28616. public function getFirstArgument()
  28617. {
  28618. $isOption = false;
  28619. foreach ($this->tokens as $i => $token) {
  28620. if ($token && '-' === $token[0]) {
  28621. if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) {
  28622. continue;
  28623. }
  28624. $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
  28625. if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
  28626. } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
  28627. $isOption = true;
  28628. }
  28629. continue;
  28630. }
  28631. if ($isOption) {
  28632. $isOption = false;
  28633. continue;
  28634. }
  28635. return $token;
  28636. }
  28637. return null;
  28638. }
  28639. public function hasParameterOption($values, bool $onlyParams = false)
  28640. {
  28641. $values = (array) $values;
  28642. foreach ($this->tokens as $token) {
  28643. if ($onlyParams && '--' === $token) {
  28644. return false;
  28645. }
  28646. foreach ($values as $value) {
  28647. $leading = str_starts_with($value, '--') ? $value.'=' : $value;
  28648. if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) {
  28649. return true;
  28650. }
  28651. }
  28652. }
  28653. return false;
  28654. }
  28655. public function getParameterOption($values, $default = false, bool $onlyParams = false)
  28656. {
  28657. $values = (array) $values;
  28658. $tokens = $this->tokens;
  28659. while (0 < \count($tokens)) {
  28660. $token = array_shift($tokens);
  28661. if ($onlyParams && '--' === $token) {
  28662. return $default;
  28663. }
  28664. foreach ($values as $value) {
  28665. if ($token === $value) {
  28666. return array_shift($tokens);
  28667. }
  28668. $leading = str_starts_with($value, '--') ? $value.'=' : $value;
  28669. if ('' !== $leading && str_starts_with($token, $leading)) {
  28670. return substr($token, \strlen($leading));
  28671. }
  28672. }
  28673. }
  28674. return $default;
  28675. }
  28676. public function __toString()
  28677. {
  28678. $tokens = array_map(function ($token) {
  28679. if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
  28680. return $match[1].$this->escapeToken($match[2]);
  28681. }
  28682. if ($token && '-' !== $token[0]) {
  28683. return $this->escapeToken($token);
  28684. }
  28685. return $token;
  28686. }, $this->tokens);
  28687. return implode(' ', $tokens);
  28688. }
  28689. }
  28690. <?php
  28691. namespace Symfony\Component\Console\Input;
  28692. use Symfony\Component\Console\Exception\InvalidArgumentException;
  28693. use Symfony\Component\Console\Exception\LogicException;
  28694. class InputArgument
  28695. {
  28696. public const REQUIRED = 1;
  28697. public const OPTIONAL = 2;
  28698. public const IS_ARRAY = 4;
  28699. private $name;
  28700. private $mode;
  28701. private $default;
  28702. private $description;
  28703. public function __construct(string $name, ?int $mode = null, string $description = '', $default = null)
  28704. {
  28705. if (null === $mode) {
  28706. $mode = self::OPTIONAL;
  28707. } elseif ($mode > 7 || $mode < 1) {
  28708. throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
  28709. }
  28710. $this->name = $name;
  28711. $this->mode = $mode;
  28712. $this->description = $description;
  28713. $this->setDefault($default);
  28714. }
  28715. public function getName()
  28716. {
  28717. return $this->name;
  28718. }
  28719. public function isRequired()
  28720. {
  28721. return self::REQUIRED === (self::REQUIRED & $this->mode);
  28722. }
  28723. public function isArray()
  28724. {
  28725. return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
  28726. }
  28727. public function setDefault($default = null)
  28728. {
  28729. if ($this->isRequired() && null !== $default) {
  28730. throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
  28731. }
  28732. if ($this->isArray()) {
  28733. if (null === $default) {
  28734. $default = [];
  28735. } elseif (!\is_array($default)) {
  28736. throw new LogicException('A default value for an array argument must be an array.');
  28737. }
  28738. }
  28739. $this->default = $default;
  28740. }
  28741. public function getDefault()
  28742. {
  28743. return $this->default;
  28744. }
  28745. public function getDescription()
  28746. {
  28747. return $this->description;
  28748. }
  28749. }
  28750. <?php
  28751. namespace Symfony\Component\Console\Input;
  28752. interface InputAwareInterface
  28753. {
  28754. public function setInput(InputInterface $input);
  28755. }
  28756. <?php
  28757. namespace Symfony\Component\Console\Input;
  28758. use Symfony\Component\Console\Exception\InvalidArgumentException;
  28759. use Symfony\Component\Console\Exception\LogicException;
  28760. class InputOption
  28761. {
  28762. public const VALUE_NONE = 1;
  28763. public const VALUE_REQUIRED = 2;
  28764. public const VALUE_OPTIONAL = 4;
  28765. public const VALUE_IS_ARRAY = 8;
  28766. public const VALUE_NEGATABLE = 16;
  28767. private $name;
  28768. private $shortcut;
  28769. private $mode;
  28770. private $default;
  28771. private $description;
  28772. public function __construct(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)
  28773. {
  28774. if (str_starts_with($name, '--')) {
  28775. $name = substr($name, 2);
  28776. }
  28777. if (empty($name)) {
  28778. throw new InvalidArgumentException('An option name cannot be empty.');
  28779. }
  28780. if ('' === $shortcut || [] === $shortcut || false === $shortcut) {
  28781. $shortcut = null;
  28782. }
  28783. if (null !== $shortcut) {
  28784. if (\is_array($shortcut)) {
  28785. $shortcut = implode('|', $shortcut);
  28786. }
  28787. $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
  28788. $shortcuts = array_filter($shortcuts, 'strlen');
  28789. $shortcut = implode('|', $shortcuts);
  28790. if ('' === $shortcut) {
  28791. throw new InvalidArgumentException('An option shortcut cannot be empty.');
  28792. }
  28793. }
  28794. if (null === $mode) {
  28795. $mode = self::VALUE_NONE;
  28796. } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) {
  28797. throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
  28798. }
  28799. $this->name = $name;
  28800. $this->shortcut = $shortcut;
  28801. $this->mode = $mode;
  28802. $this->description = $description;
  28803. if ($this->isArray() && !$this->acceptValue()) {
  28804. throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
  28805. }
  28806. if ($this->isNegatable() && $this->acceptValue()) {
  28807. throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.');
  28808. }
  28809. $this->setDefault($default);
  28810. }
  28811. public function getShortcut()
  28812. {
  28813. return $this->shortcut;
  28814. }
  28815. public function getName()
  28816. {
  28817. return $this->name;
  28818. }
  28819. public function acceptValue()
  28820. {
  28821. return $this->isValueRequired() || $this->isValueOptional();
  28822. }
  28823. public function isValueRequired()
  28824. {
  28825. return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
  28826. }
  28827. public function isValueOptional()
  28828. {
  28829. return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
  28830. }
  28831. public function isArray()
  28832. {
  28833. return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
  28834. }
  28835. public function isNegatable(): bool
  28836. {
  28837. return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);
  28838. }
  28839. public function setDefault($default = null)
  28840. {
  28841. if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
  28842. throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
  28843. }
  28844. if ($this->isArray()) {
  28845. if (null === $default) {
  28846. $default = [];
  28847. } elseif (!\is_array($default)) {
  28848. throw new LogicException('A default value for an array option must be an array.');
  28849. }
  28850. }
  28851. $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false;
  28852. }
  28853. public function getDefault()
  28854. {
  28855. return $this->default;
  28856. }
  28857. public function getDescription()
  28858. {
  28859. return $this->description;
  28860. }
  28861. public function equals(self $option)
  28862. {
  28863. return $option->getName() === $this->getName()
  28864. && $option->getShortcut() === $this->getShortcut()
  28865. && $option->getDefault() === $this->getDefault()
  28866. && $option->isNegatable() === $this->isNegatable()
  28867. && $option->isArray() === $this->isArray()
  28868. && $option->isValueRequired() === $this->isValueRequired()
  28869. && $option->isValueOptional() === $this->isValueOptional()
  28870. ;
  28871. }
  28872. }
  28873. <?php
  28874. namespace Symfony\Component\Console\Input;
  28875. use Symfony\Component\Console\Exception\InvalidArgumentException;
  28876. use Symfony\Component\Console\Exception\LogicException;
  28877. class InputDefinition
  28878. {
  28879. private $arguments;
  28880. private $requiredCount;
  28881. private $lastArrayArgument;
  28882. private $lastOptionalArgument;
  28883. private $options;
  28884. private $negations;
  28885. private $shortcuts;
  28886. public function __construct(array $definition = [])
  28887. {
  28888. $this->setDefinition($definition);
  28889. }
  28890. public function setDefinition(array $definition)
  28891. {
  28892. $arguments = [];
  28893. $options = [];
  28894. foreach ($definition as $item) {
  28895. if ($item instanceof InputOption) {
  28896. $options[] = $item;
  28897. } else {
  28898. $arguments[] = $item;
  28899. }
  28900. }
  28901. $this->setArguments($arguments);
  28902. $this->setOptions($options);
  28903. }
  28904. public function setArguments(array $arguments = [])
  28905. {
  28906. $this->arguments = [];
  28907. $this->requiredCount = 0;
  28908. $this->lastOptionalArgument = null;
  28909. $this->lastArrayArgument = null;
  28910. $this->addArguments($arguments);
  28911. }
  28912. public function addArguments(?array $arguments = [])
  28913. {
  28914. if (null !== $arguments) {
  28915. foreach ($arguments as $argument) {
  28916. $this->addArgument($argument);
  28917. }
  28918. }
  28919. }
  28920. public function addArgument(InputArgument $argument)
  28921. {
  28922. if (isset($this->arguments[$argument->getName()])) {
  28923. throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
  28924. }
  28925. if (null !== $this->lastArrayArgument) {
  28926. throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName()));
  28927. }
  28928. if ($argument->isRequired() && null !== $this->lastOptionalArgument) {
  28929. throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName()));
  28930. }
  28931. if ($argument->isArray()) {
  28932. $this->lastArrayArgument = $argument;
  28933. }
  28934. if ($argument->isRequired()) {
  28935. ++$this->requiredCount;
  28936. } else {
  28937. $this->lastOptionalArgument = $argument;
  28938. }
  28939. $this->arguments[$argument->getName()] = $argument;
  28940. }
  28941. public function getArgument($name)
  28942. {
  28943. if (!$this->hasArgument($name)) {
  28944. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  28945. }
  28946. $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
  28947. return $arguments[$name];
  28948. }
  28949. public function hasArgument($name)
  28950. {
  28951. $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;
  28952. return isset($arguments[$name]);
  28953. }
  28954. public function getArguments()
  28955. {
  28956. return $this->arguments;
  28957. }
  28958. public function getArgumentCount()
  28959. {
  28960. return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
  28961. }
  28962. public function getArgumentRequiredCount()
  28963. {
  28964. return $this->requiredCount;
  28965. }
  28966. public function getArgumentDefaults()
  28967. {
  28968. $values = [];
  28969. foreach ($this->arguments as $argument) {
  28970. $values[$argument->getName()] = $argument->getDefault();
  28971. }
  28972. return $values;
  28973. }
  28974. public function setOptions(array $options = [])
  28975. {
  28976. $this->options = [];
  28977. $this->shortcuts = [];
  28978. $this->negations = [];
  28979. $this->addOptions($options);
  28980. }
  28981. public function addOptions(array $options = [])
  28982. {
  28983. foreach ($options as $option) {
  28984. $this->addOption($option);
  28985. }
  28986. }
  28987. public function addOption(InputOption $option)
  28988. {
  28989. if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
  28990. throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
  28991. }
  28992. if (isset($this->negations[$option->getName()])) {
  28993. throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
  28994. }
  28995. if ($option->getShortcut()) {
  28996. foreach (explode('|', $option->getShortcut()) as $shortcut) {
  28997. if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
  28998. throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
  28999. }
  29000. }
  29001. }
  29002. $this->options[$option->getName()] = $option;
  29003. if ($option->getShortcut()) {
  29004. foreach (explode('|', $option->getShortcut()) as $shortcut) {
  29005. $this->shortcuts[$shortcut] = $option->getName();
  29006. }
  29007. }
  29008. if ($option->isNegatable()) {
  29009. $negatedName = 'no-'.$option->getName();
  29010. if (isset($this->options[$negatedName])) {
  29011. throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName));
  29012. }
  29013. $this->negations[$negatedName] = $option->getName();
  29014. }
  29015. }
  29016. public function getOption(string $name)
  29017. {
  29018. if (!$this->hasOption($name)) {
  29019. throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
  29020. }
  29021. return $this->options[$name];
  29022. }
  29023. public function hasOption(string $name)
  29024. {
  29025. return isset($this->options[$name]);
  29026. }
  29027. public function getOptions()
  29028. {
  29029. return $this->options;
  29030. }
  29031. public function hasShortcut(string $name)
  29032. {
  29033. return isset($this->shortcuts[$name]);
  29034. }
  29035. public function hasNegation(string $name): bool
  29036. {
  29037. return isset($this->negations[$name]);
  29038. }
  29039. public function getOptionForShortcut(string $shortcut)
  29040. {
  29041. return $this->getOption($this->shortcutToName($shortcut));
  29042. }
  29043. public function getOptionDefaults()
  29044. {
  29045. $values = [];
  29046. foreach ($this->options as $option) {
  29047. $values[$option->getName()] = $option->getDefault();
  29048. }
  29049. return $values;
  29050. }
  29051. public function shortcutToName(string $shortcut): string
  29052. {
  29053. if (!isset($this->shortcuts[$shortcut])) {
  29054. throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
  29055. }
  29056. return $this->shortcuts[$shortcut];
  29057. }
  29058. public function negationToName(string $negation): string
  29059. {
  29060. if (!isset($this->negations[$negation])) {
  29061. throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation));
  29062. }
  29063. return $this->negations[$negation];
  29064. }
  29065. public function getSynopsis(bool $short = false)
  29066. {
  29067. $elements = [];
  29068. if ($short && $this->getOptions()) {
  29069. $elements[] = '[options]';
  29070. } elseif (!$short) {
  29071. foreach ($this->getOptions() as $option) {
  29072. $value = '';
  29073. if ($option->acceptValue()) {
  29074. $value = sprintf(
  29075. ' %s%s%s',
  29076. $option->isValueOptional() ? '[' : '',
  29077. strtoupper($option->getName()),
  29078. $option->isValueOptional() ? ']' : ''
  29079. );
  29080. }
  29081. $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
  29082. $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : '';
  29083. $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation);
  29084. }
  29085. }
  29086. if (\count($elements) && $this->getArguments()) {
  29087. $elements[] = '[--]';
  29088. }
  29089. $tail = '';
  29090. foreach ($this->getArguments() as $argument) {
  29091. $element = '<'.$argument->getName().'>';
  29092. if ($argument->isArray()) {
  29093. $element .= '...';
  29094. }
  29095. if (!$argument->isRequired()) {
  29096. $element = '['.$element;
  29097. $tail .= ']';
  29098. }
  29099. $elements[] = $element;
  29100. }
  29101. return implode(' ', $elements).$tail;
  29102. }
  29103. }
  29104. <?php
  29105. namespace Symfony\Component\Console\Input;
  29106. use Symfony\Component\Console\Exception\InvalidArgumentException;
  29107. class StringInput extends ArgvInput
  29108. {
  29109. public const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
  29110. public const REGEX_UNQUOTED_STRING = '([^\s\\\\]+?)';
  29111. public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
  29112. public function __construct(string $input)
  29113. {
  29114. parent::__construct([]);
  29115. $this->setTokens($this->tokenize($input));
  29116. }
  29117. private function tokenize(string $input): array
  29118. {
  29119. $tokens = [];
  29120. $length = \strlen($input);
  29121. $cursor = 0;
  29122. $token = null;
  29123. while ($cursor < $length) {
  29124. if ('\\' === $input[$cursor]) {
  29125. $token .= $input[++$cursor] ?? '';
  29126. ++$cursor;
  29127. continue;
  29128. }
  29129. if (preg_match('/\s+/A', $input, $match, 0, $cursor)) {
  29130. if (null !== $token) {
  29131. $tokens[] = $token;
  29132. $token = null;
  29133. }
  29134. } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) {
  29135. $token .= $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1)));
  29136. } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
  29137. $token .= stripcslashes(substr($match[0], 1, -1));
  29138. } elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
  29139. $token .= $match[1];
  29140. } else {
  29141. throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10)));
  29142. }
  29143. $cursor += \strlen($match[0]);
  29144. }
  29145. if (null !== $token) {
  29146. $tokens[] = $token;
  29147. }
  29148. return $tokens;
  29149. }
  29150. }
  29151. <?php
  29152. namespace Symfony\Component\Console\Input;
  29153. use Symfony\Component\Console\Exception\InvalidArgumentException;
  29154. use Symfony\Component\Console\Exception\RuntimeException;
  29155. abstract class Input implements InputInterface, StreamableInputInterface
  29156. {
  29157. protected $definition;
  29158. protected $stream;
  29159. protected $options = [];
  29160. protected $arguments = [];
  29161. protected $interactive = true;
  29162. public function __construct(?InputDefinition $definition = null)
  29163. {
  29164. if (null === $definition) {
  29165. $this->definition = new InputDefinition();
  29166. } else {
  29167. $this->bind($definition);
  29168. $this->validate();
  29169. }
  29170. }
  29171. public function bind(InputDefinition $definition)
  29172. {
  29173. $this->arguments = [];
  29174. $this->options = [];
  29175. $this->definition = $definition;
  29176. $this->parse();
  29177. }
  29178. abstract protected function parse();
  29179. public function validate()
  29180. {
  29181. $definition = $this->definition;
  29182. $givenArguments = $this->arguments;
  29183. $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
  29184. return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
  29185. });
  29186. if (\count($missingArguments) > 0) {
  29187. throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
  29188. }
  29189. }
  29190. public function isInteractive()
  29191. {
  29192. return $this->interactive;
  29193. }
  29194. public function setInteractive(bool $interactive)
  29195. {
  29196. $this->interactive = $interactive;
  29197. }
  29198. public function getArguments()
  29199. {
  29200. return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
  29201. }
  29202. public function getArgument(string $name)
  29203. {
  29204. if (!$this->definition->hasArgument($name)) {
  29205. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  29206. }
  29207. return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
  29208. }
  29209. public function setArgument(string $name, $value)
  29210. {
  29211. if (!$this->definition->hasArgument($name)) {
  29212. throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
  29213. }
  29214. $this->arguments[$name] = $value;
  29215. }
  29216. public function hasArgument(string $name)
  29217. {
  29218. return $this->definition->hasArgument($name);
  29219. }
  29220. public function getOptions()
  29221. {
  29222. return array_merge($this->definition->getOptionDefaults(), $this->options);
  29223. }
  29224. public function getOption(string $name)
  29225. {
  29226. if ($this->definition->hasNegation($name)) {
  29227. if (null === $value = $this->getOption($this->definition->negationToName($name))) {
  29228. return $value;
  29229. }
  29230. return !$value;
  29231. }
  29232. if (!$this->definition->hasOption($name)) {
  29233. throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
  29234. }
  29235. return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
  29236. }
  29237. public function setOption(string $name, $value)
  29238. {
  29239. if ($this->definition->hasNegation($name)) {
  29240. $this->options[$this->definition->negationToName($name)] = !$value;
  29241. return;
  29242. } elseif (!$this->definition->hasOption($name)) {
  29243. throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
  29244. }
  29245. $this->options[$name] = $value;
  29246. }
  29247. public function hasOption(string $name)
  29248. {
  29249. return $this->definition->hasOption($name) || $this->definition->hasNegation($name);
  29250. }
  29251. public function escapeToken(string $token)
  29252. {
  29253. return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
  29254. }
  29255. public function setStream($stream)
  29256. {
  29257. $this->stream = $stream;
  29258. }
  29259. public function getStream()
  29260. {
  29261. return $this->stream;
  29262. }
  29263. }
  29264. <?php
  29265. namespace Symfony\Component\Console\Input;
  29266. use Symfony\Component\Console\Exception\InvalidArgumentException;
  29267. use Symfony\Component\Console\Exception\RuntimeException;
  29268. interface InputInterface
  29269. {
  29270. public function getFirstArgument();
  29271. public function hasParameterOption($values, bool $onlyParams = false);
  29272. public function getParameterOption($values, $default = false, bool $onlyParams = false);
  29273. public function bind(InputDefinition $definition);
  29274. public function validate();
  29275. public function getArguments();
  29276. public function getArgument(string $name);
  29277. public function setArgument(string $name, $value);
  29278. public function hasArgument(string $name);
  29279. public function getOptions();
  29280. public function getOption(string $name);
  29281. public function setOption(string $name, $value);
  29282. public function hasOption(string $name);
  29283. public function isInteractive();
  29284. public function setInteractive(bool $interactive);
  29285. }
  29286. <?php
  29287. namespace Symfony\Component\Console;
  29288. class Terminal
  29289. {
  29290. private static $width;
  29291. private static $height;
  29292. private static $stty;
  29293. public function getWidth()
  29294. {
  29295. $width = getenv('COLUMNS');
  29296. if (false !== $width) {
  29297. return (int) trim($width);
  29298. }
  29299. if (null === self::$width) {
  29300. self::initDimensions();
  29301. }
  29302. return self::$width ?: 80;
  29303. }
  29304. public function getHeight()
  29305. {
  29306. $height = getenv('LINES');
  29307. if (false !== $height) {
  29308. return (int) trim($height);
  29309. }
  29310. if (null === self::$height) {
  29311. self::initDimensions();
  29312. }
  29313. return self::$height ?: 50;
  29314. }
  29315. public static function hasSttyAvailable(): bool
  29316. {
  29317. if (null !== self::$stty) {
  29318. return self::$stty;
  29319. }
  29320. if (!\function_exists('shell_exec')) {
  29321. return false;
  29322. }
  29323. return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
  29324. }
  29325. private static function initDimensions()
  29326. {
  29327. if ('\\' === \DIRECTORY_SEPARATOR) {
  29328. $ansicon = getenv('ANSICON');
  29329. if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) {
  29330. self::$width = (int) $matches[1];
  29331. self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
  29332. } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
  29333. self::initDimensionsUsingStty();
  29334. } elseif (null !== $dimensions = self::getConsoleMode()) {
  29335. self::$width = (int) $dimensions[0];
  29336. self::$height = (int) $dimensions[1];
  29337. }
  29338. } else {
  29339. self::initDimensionsUsingStty();
  29340. }
  29341. }
  29342. private static function hasVt100Support(): bool
  29343. {
  29344. return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));
  29345. }
  29346. private static function initDimensionsUsingStty()
  29347. {
  29348. if ($sttyString = self::getSttyColumns()) {
  29349. if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
  29350. self::$width = (int) $matches[2];
  29351. self::$height = (int) $matches[1];
  29352. } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
  29353. self::$width = (int) $matches[2];
  29354. self::$height = (int) $matches[1];
  29355. }
  29356. }
  29357. }
  29358. private static function getConsoleMode(): ?array
  29359. {
  29360. $info = self::readFromProcess('mode CON');
  29361. if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
  29362. return null;
  29363. }
  29364. return [(int) $matches[2], (int) $matches[1]];
  29365. }
  29366. private static function getSttyColumns(): ?string
  29367. {
  29368. return self::readFromProcess('stty -a | grep columns');
  29369. }
  29370. private static function readFromProcess(string $command): ?string
  29371. {
  29372. if (!\function_exists('proc_open')) {
  29373. return null;
  29374. }
  29375. $descriptorspec = [
  29376. 1 => ['pipe', 'w'],
  29377. 2 => ['pipe', 'w'],
  29378. ];
  29379. $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;
  29380. if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) {
  29381. return null;
  29382. }
  29383. $info = stream_get_contents($pipes[1]);
  29384. fclose($pipes[1]);
  29385. fclose($pipes[2]);
  29386. proc_close($process);
  29387. if ($cp) {
  29388. sapi_windows_cp_set($cp);
  29389. }
  29390. return $info;
  29391. }
  29392. }
  29393. <?php
  29394. namespace Symfony\Component\Console\CI;
  29395. use Symfony\Component\Console\Output\OutputInterface;
  29396. class GithubActionReporter
  29397. {
  29398. private $output;
  29399. private const ESCAPED_DATA = [
  29400. '%' => '%25',
  29401. "\r" => '%0D',
  29402. "\n" => '%0A',
  29403. ];
  29404. private const ESCAPED_PROPERTIES = [
  29405. '%' => '%25',
  29406. "\r" => '%0D',
  29407. "\n" => '%0A',
  29408. ':' => '%3A',
  29409. ',' => '%2C',
  29410. ];
  29411. public function __construct(OutputInterface $output)
  29412. {
  29413. $this->output = $output;
  29414. }
  29415. public static function isGithubActionEnvironment(): bool
  29416. {
  29417. return false !== getenv('GITHUB_ACTIONS');
  29418. }
  29419. public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
  29420. {
  29421. $this->log('error', $message, $file, $line, $col);
  29422. }
  29423. public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
  29424. {
  29425. $this->log('warning', $message, $file, $line, $col);
  29426. }
  29427. public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
  29428. {
  29429. $this->log('debug', $message, $file, $line, $col);
  29430. }
  29431. private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
  29432. {
  29433. $message = strtr($message, self::ESCAPED_DATA);
  29434. if (!$file) {
  29435. $this->output->writeln(sprintf('::%s::%s', $type, $message));
  29436. return;
  29437. }
  29438. $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message));
  29439. }
  29440. }
  29441. <?php
  29442. namespace Symfony\Component\Console\Output;
  29443. use Symfony\Component\Console\Exception\InvalidArgumentException;
  29444. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29445. class TrimmedBufferOutput extends Output
  29446. {
  29447. private $maxLength;
  29448. private $buffer = '';
  29449. public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
  29450. {
  29451. if ($maxLength <= 0) {
  29452. throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
  29453. }
  29454. parent::__construct($verbosity, $decorated, $formatter);
  29455. $this->maxLength = $maxLength;
  29456. }
  29457. public function fetch()
  29458. {
  29459. $content = $this->buffer;
  29460. $this->buffer = '';
  29461. return $content;
  29462. }
  29463. protected function doWrite(string $message, bool $newline)
  29464. {
  29465. $this->buffer .= $message;
  29466. if ($newline) {
  29467. $this->buffer .= \PHP_EOL;
  29468. }
  29469. $this->buffer = substr($this->buffer, 0 - $this->maxLength);
  29470. }
  29471. }
  29472. <?php
  29473. namespace Symfony\Component\Console\Output;
  29474. interface ConsoleOutputInterface extends OutputInterface
  29475. {
  29476. public function getErrorOutput();
  29477. public function setErrorOutput(OutputInterface $error);
  29478. public function section(): ConsoleSectionOutput;
  29479. }
  29480. <?php
  29481. namespace Symfony\Component\Console\Output;
  29482. class BufferedOutput extends Output
  29483. {
  29484. private $buffer = '';
  29485. public function fetch()
  29486. {
  29487. $content = $this->buffer;
  29488. $this->buffer = '';
  29489. return $content;
  29490. }
  29491. protected function doWrite(string $message, bool $newline)
  29492. {
  29493. $this->buffer .= $message;
  29494. if ($newline) {
  29495. $this->buffer .= \PHP_EOL;
  29496. }
  29497. }
  29498. }
  29499. <?php
  29500. namespace Symfony\Component\Console\Output;
  29501. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29502. interface OutputInterface
  29503. {
  29504. public const VERBOSITY_QUIET = 16;
  29505. public const VERBOSITY_NORMAL = 32;
  29506. public const VERBOSITY_VERBOSE = 64;
  29507. public const VERBOSITY_VERY_VERBOSE = 128;
  29508. public const VERBOSITY_DEBUG = 256;
  29509. public const OUTPUT_NORMAL = 1;
  29510. public const OUTPUT_RAW = 2;
  29511. public const OUTPUT_PLAIN = 4;
  29512. public function write($messages, bool $newline = false, int $options = 0);
  29513. public function writeln($messages, int $options = 0);
  29514. public function setVerbosity(int $level);
  29515. public function getVerbosity();
  29516. public function isQuiet();
  29517. public function isVerbose();
  29518. public function isVeryVerbose();
  29519. public function isDebug();
  29520. public function setDecorated(bool $decorated);
  29521. public function isDecorated();
  29522. public function setFormatter(OutputFormatterInterface $formatter);
  29523. public function getFormatter();
  29524. }
  29525. <?php
  29526. namespace Symfony\Component\Console\Output;
  29527. use Symfony\Component\Console\Formatter\OutputFormatter;
  29528. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29529. abstract class Output implements OutputInterface
  29530. {
  29531. private $verbosity;
  29532. private $formatter;
  29533. public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
  29534. {
  29535. $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL;
  29536. $this->formatter = $formatter ?? new OutputFormatter();
  29537. $this->formatter->setDecorated($decorated);
  29538. }
  29539. public function setFormatter(OutputFormatterInterface $formatter)
  29540. {
  29541. $this->formatter = $formatter;
  29542. }
  29543. public function getFormatter()
  29544. {
  29545. return $this->formatter;
  29546. }
  29547. public function setDecorated(bool $decorated)
  29548. {
  29549. $this->formatter->setDecorated($decorated);
  29550. }
  29551. public function isDecorated()
  29552. {
  29553. return $this->formatter->isDecorated();
  29554. }
  29555. public function setVerbosity(int $level)
  29556. {
  29557. $this->verbosity = $level;
  29558. }
  29559. public function getVerbosity()
  29560. {
  29561. return $this->verbosity;
  29562. }
  29563. public function isQuiet()
  29564. {
  29565. return self::VERBOSITY_QUIET === $this->verbosity;
  29566. }
  29567. public function isVerbose()
  29568. {
  29569. return self::VERBOSITY_VERBOSE <= $this->verbosity;
  29570. }
  29571. public function isVeryVerbose()
  29572. {
  29573. return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
  29574. }
  29575. public function isDebug()
  29576. {
  29577. return self::VERBOSITY_DEBUG <= $this->verbosity;
  29578. }
  29579. public function writeln($messages, int $options = self::OUTPUT_NORMAL)
  29580. {
  29581. $this->write($messages, true, $options);
  29582. }
  29583. public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
  29584. {
  29585. if (!is_iterable($messages)) {
  29586. $messages = [$messages];
  29587. }
  29588. $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
  29589. $type = $types & $options ?: self::OUTPUT_NORMAL;
  29590. $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
  29591. $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
  29592. if ($verbosity > $this->getVerbosity()) {
  29593. return;
  29594. }
  29595. foreach ($messages as $message) {
  29596. switch ($type) {
  29597. case OutputInterface::OUTPUT_NORMAL:
  29598. $message = $this->formatter->format($message);
  29599. break;
  29600. case OutputInterface::OUTPUT_RAW:
  29601. break;
  29602. case OutputInterface::OUTPUT_PLAIN:
  29603. $message = strip_tags($this->formatter->format($message));
  29604. break;
  29605. }
  29606. $this->doWrite($message ?? '', $newline);
  29607. }
  29608. }
  29609. abstract protected function doWrite(string $message, bool $newline);
  29610. }
  29611. <?php
  29612. namespace Symfony\Component\Console\Output;
  29613. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29614. use Symfony\Component\Console\Helper\Helper;
  29615. use Symfony\Component\Console\Terminal;
  29616. class ConsoleSectionOutput extends StreamOutput
  29617. {
  29618. private $content = [];
  29619. private $lines = 0;
  29620. private $sections;
  29621. private $terminal;
  29622. public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter)
  29623. {
  29624. parent::__construct($stream, $verbosity, $decorated, $formatter);
  29625. array_unshift($sections, $this);
  29626. $this->sections = &$sections;
  29627. $this->terminal = new Terminal();
  29628. }
  29629. public function clear(?int $lines = null)
  29630. {
  29631. if (empty($this->content) || !$this->isDecorated()) {
  29632. return;
  29633. }
  29634. if ($lines) {
  29635. array_splice($this->content, -($lines * 2));
  29636. } else {
  29637. $lines = $this->lines;
  29638. $this->content = [];
  29639. }
  29640. $this->lines -= $lines;
  29641. parent::doWrite($this->popStreamContentUntilCurrentSection($lines), false);
  29642. }
  29643. public function overwrite($message)
  29644. {
  29645. $this->clear();
  29646. $this->writeln($message);
  29647. }
  29648. public function getContent(): string
  29649. {
  29650. return implode('', $this->content);
  29651. }
  29652. public function addContent(string $input)
  29653. {
  29654. foreach (explode(\PHP_EOL, $input) as $lineContent) {
  29655. $this->lines += ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;
  29656. $this->content[] = $lineContent;
  29657. $this->content[] = \PHP_EOL;
  29658. }
  29659. }
  29660. protected function doWrite(string $message, bool $newline)
  29661. {
  29662. if (!$this->isDecorated()) {
  29663. parent::doWrite($message, $newline);
  29664. return;
  29665. }
  29666. $erasedContent = $this->popStreamContentUntilCurrentSection();
  29667. $this->addContent($message);
  29668. parent::doWrite($message, true);
  29669. parent::doWrite($erasedContent, false);
  29670. }
  29671. private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string
  29672. {
  29673. $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;
  29674. $erasedContent = [];
  29675. foreach ($this->sections as $section) {
  29676. if ($section === $this) {
  29677. break;
  29678. }
  29679. $numberOfLinesToClear += $section->lines;
  29680. $erasedContent[] = $section->getContent();
  29681. }
  29682. if ($numberOfLinesToClear > 0) {
  29683. parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false);
  29684. parent::doWrite("\x1b[0J", false);
  29685. }
  29686. return implode('', array_reverse($erasedContent));
  29687. }
  29688. private function getDisplayLength(string $text): int
  29689. {
  29690. return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace("\t", ' ', $text)));
  29691. }
  29692. }
  29693. <?php
  29694. namespace Symfony\Component\Console\Output;
  29695. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29696. class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
  29697. {
  29698. private $stderr;
  29699. private $consoleSectionOutputs = [];
  29700. public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
  29701. {
  29702. parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
  29703. if (null === $formatter) {
  29704. $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);
  29705. return;
  29706. }
  29707. $actualDecorated = $this->isDecorated();
  29708. $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
  29709. if (null === $decorated) {
  29710. $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
  29711. }
  29712. }
  29713. public function section(): ConsoleSectionOutput
  29714. {
  29715. return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
  29716. }
  29717. public function setDecorated(bool $decorated)
  29718. {
  29719. parent::setDecorated($decorated);
  29720. $this->stderr->setDecorated($decorated);
  29721. }
  29722. public function setFormatter(OutputFormatterInterface $formatter)
  29723. {
  29724. parent::setFormatter($formatter);
  29725. $this->stderr->setFormatter($formatter);
  29726. }
  29727. public function setVerbosity(int $level)
  29728. {
  29729. parent::setVerbosity($level);
  29730. $this->stderr->setVerbosity($level);
  29731. }
  29732. public function getErrorOutput()
  29733. {
  29734. return $this->stderr;
  29735. }
  29736. public function setErrorOutput(OutputInterface $error)
  29737. {
  29738. $this->stderr = $error;
  29739. }
  29740. protected function hasStdoutSupport()
  29741. {
  29742. return false === $this->isRunningOS400();
  29743. }
  29744. protected function hasStderrSupport()
  29745. {
  29746. return false === $this->isRunningOS400();
  29747. }
  29748. private function isRunningOS400(): bool
  29749. {
  29750. $checks = [
  29751. \function_exists('php_uname') ? php_uname('s') : '',
  29752. getenv('OSTYPE'),
  29753. \PHP_OS,
  29754. ];
  29755. return false !== stripos(implode(';', $checks), 'OS400');
  29756. }
  29757. private function openOutputStream()
  29758. {
  29759. if (!$this->hasStdoutSupport()) {
  29760. return fopen('php://output', 'w');
  29761. }
  29762. return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));
  29763. }
  29764. private function openErrorStream()
  29765. {
  29766. if (!$this->hasStderrSupport()) {
  29767. return fopen('php://output', 'w');
  29768. }
  29769. return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));
  29770. }
  29771. }
  29772. <?php
  29773. namespace Symfony\Component\Console\Output;
  29774. use Symfony\Component\Console\Formatter\NullOutputFormatter;
  29775. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29776. class NullOutput implements OutputInterface
  29777. {
  29778. private $formatter;
  29779. public function setFormatter(OutputFormatterInterface $formatter)
  29780. {
  29781. }
  29782. public function getFormatter()
  29783. {
  29784. if ($this->formatter) {
  29785. return $this->formatter;
  29786. }
  29787. return $this->formatter = new NullOutputFormatter();
  29788. }
  29789. public function setDecorated(bool $decorated)
  29790. {
  29791. }
  29792. public function isDecorated()
  29793. {
  29794. return false;
  29795. }
  29796. public function setVerbosity(int $level)
  29797. {
  29798. }
  29799. public function getVerbosity()
  29800. {
  29801. return self::VERBOSITY_QUIET;
  29802. }
  29803. public function isQuiet()
  29804. {
  29805. return true;
  29806. }
  29807. public function isVerbose()
  29808. {
  29809. return false;
  29810. }
  29811. public function isVeryVerbose()
  29812. {
  29813. return false;
  29814. }
  29815. public function isDebug()
  29816. {
  29817. return false;
  29818. }
  29819. public function writeln($messages, int $options = self::OUTPUT_NORMAL)
  29820. {
  29821. }
  29822. public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
  29823. {
  29824. }
  29825. }
  29826. <?php
  29827. namespace Symfony\Component\Console\Output;
  29828. use Symfony\Component\Console\Exception\InvalidArgumentException;
  29829. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  29830. class StreamOutput extends Output
  29831. {
  29832. private $stream;
  29833. public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
  29834. {
  29835. if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
  29836. throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
  29837. }
  29838. $this->stream = $stream;
  29839. if (null === $decorated) {
  29840. $decorated = $this->hasColorSupport();
  29841. }
  29842. parent::__construct($verbosity, $decorated, $formatter);
  29843. }
  29844. public function getStream()
  29845. {
  29846. return $this->stream;
  29847. }
  29848. protected function doWrite(string $message, bool $newline)
  29849. {
  29850. if ($newline) {
  29851. $message .= \PHP_EOL;
  29852. }
  29853. @fwrite($this->stream, $message);
  29854. fflush($this->stream);
  29855. }
  29856. protected function hasColorSupport()
  29857. {
  29858. if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) {
  29859. return false;
  29860. }
  29861. if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) {
  29862. return false;
  29863. }
  29864. if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) {
  29865. return true;
  29866. }
  29867. if ('Hyper' === getenv('TERM_PROGRAM')
  29868. || false !== getenv('COLORTERM')
  29869. || false !== getenv('ANSICON')
  29870. || 'ON' === getenv('ConEmuANSI')
  29871. ) {
  29872. return true;
  29873. }
  29874. if ('dumb' === $term = (string) getenv('TERM')) {
  29875. return false;
  29876. }
  29877. return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term);
  29878. }
  29879. }
  29880. <?php
  29881. namespace Symfony\Component\Console\Completion\Output;
  29882. use Symfony\Component\Console\Completion\CompletionSuggestions;
  29883. use Symfony\Component\Console\Output\OutputInterface;
  29884. class BashCompletionOutput implements CompletionOutputInterface
  29885. {
  29886. public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
  29887. {
  29888. $values = $suggestions->getValueSuggestions();
  29889. foreach ($suggestions->getOptionSuggestions() as $option) {
  29890. $values[] = '--'.$option->getName();
  29891. if ($option->isNegatable()) {
  29892. $values[] = '--no-'.$option->getName();
  29893. }
  29894. }
  29895. $output->writeln(implode("\n", $values));
  29896. }
  29897. }
  29898. <?php
  29899. namespace Symfony\Component\Console\Completion\Output;
  29900. use Symfony\Component\Console\Completion\CompletionSuggestions;
  29901. use Symfony\Component\Console\Output\OutputInterface;
  29902. interface CompletionOutputInterface
  29903. {
  29904. public function write(CompletionSuggestions $suggestions, OutputInterface $output): void;
  29905. }
  29906. <?php
  29907. namespace Symfony\Component\Console\Completion;
  29908. class Suggestion
  29909. {
  29910. private $value;
  29911. public function __construct(string $value)
  29912. {
  29913. $this->value = $value;
  29914. }
  29915. public function getValue(): string
  29916. {
  29917. return $this->value;
  29918. }
  29919. public function __toString(): string
  29920. {
  29921. return $this->getValue();
  29922. }
  29923. }
  29924. <?php
  29925. namespace Symfony\Component\Console\Completion;
  29926. use Symfony\Component\Console\Input\InputOption;
  29927. final class CompletionSuggestions
  29928. {
  29929. private $valueSuggestions = [];
  29930. private $optionSuggestions = [];
  29931. public function suggestValue($value): self
  29932. {
  29933. $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;
  29934. return $this;
  29935. }
  29936. public function suggestValues(array $values): self
  29937. {
  29938. foreach ($values as $value) {
  29939. $this->suggestValue($value);
  29940. }
  29941. return $this;
  29942. }
  29943. public function suggestOption(InputOption $option): self
  29944. {
  29945. $this->optionSuggestions[] = $option;
  29946. return $this;
  29947. }
  29948. public function suggestOptions(array $options): self
  29949. {
  29950. foreach ($options as $option) {
  29951. $this->suggestOption($option);
  29952. }
  29953. return $this;
  29954. }
  29955. public function getOptionSuggestions(): array
  29956. {
  29957. return $this->optionSuggestions;
  29958. }
  29959. public function getValueSuggestions(): array
  29960. {
  29961. return $this->valueSuggestions;
  29962. }
  29963. }
  29964. <?php
  29965. namespace Symfony\Component\Console\Completion;
  29966. use Symfony\Component\Console\Exception\RuntimeException;
  29967. use Symfony\Component\Console\Input\ArgvInput;
  29968. use Symfony\Component\Console\Input\InputDefinition;
  29969. use Symfony\Component\Console\Input\InputOption;
  29970. final class CompletionInput extends ArgvInput
  29971. {
  29972. public const TYPE_ARGUMENT_VALUE = 'argument_value';
  29973. public const TYPE_OPTION_VALUE = 'option_value';
  29974. public const TYPE_OPTION_NAME = 'option_name';
  29975. public const TYPE_NONE = 'none';
  29976. private $tokens;
  29977. private $currentIndex;
  29978. private $completionType;
  29979. private $completionName = null;
  29980. private $completionValue = '';
  29981. public static function fromString(string $inputStr, int $currentIndex): self
  29982. {
  29983. preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $inputStr, $tokens);
  29984. return self::fromTokens($tokens[0], $currentIndex);
  29985. }
  29986. public static function fromTokens(array $tokens, int $currentIndex): self
  29987. {
  29988. $input = new self($tokens);
  29989. $input->tokens = $tokens;
  29990. $input->currentIndex = $currentIndex;
  29991. return $input;
  29992. }
  29993. public function bind(InputDefinition $definition): void
  29994. {
  29995. parent::bind($definition);
  29996. $relevantToken = $this->getRelevantToken();
  29997. if ('-' === $relevantToken[0]) {
  29998. [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', ''];
  29999. $option = $this->getOptionFromToken($optionToken);
  30000. if (null === $option && !$this->isCursorFree()) {
  30001. $this->completionType = self::TYPE_OPTION_NAME;
  30002. $this->completionValue = $relevantToken;
  30003. return;
  30004. }
  30005. if (null !== $option && $option->acceptValue()) {
  30006. $this->completionType = self::TYPE_OPTION_VALUE;
  30007. $this->completionName = $option->getName();
  30008. $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');
  30009. return;
  30010. }
  30011. }
  30012. $previousToken = $this->tokens[$this->currentIndex - 1];
  30013. if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {
  30014. $previousOption = $this->getOptionFromToken($previousToken);
  30015. if (null !== $previousOption && $previousOption->acceptValue()) {
  30016. $this->completionType = self::TYPE_OPTION_VALUE;
  30017. $this->completionName = $previousOption->getName();
  30018. $this->completionValue = $relevantToken;
  30019. return;
  30020. }
  30021. }
  30022. $this->completionType = self::TYPE_ARGUMENT_VALUE;
  30023. foreach ($this->definition->getArguments() as $argumentName => $argument) {
  30024. if (!isset($this->arguments[$argumentName])) {
  30025. break;
  30026. }
  30027. $argumentValue = $this->arguments[$argumentName];
  30028. $this->completionName = $argumentName;
  30029. if (\is_array($argumentValue)) {
  30030. $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null;
  30031. } else {
  30032. $this->completionValue = $argumentValue;
  30033. }
  30034. }
  30035. if ($this->currentIndex >= \count($this->tokens)) {
  30036. if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {
  30037. $this->completionName = $argumentName;
  30038. $this->completionValue = '';
  30039. } else {
  30040. $this->completionType = self::TYPE_NONE;
  30041. $this->completionName = null;
  30042. $this->completionValue = '';
  30043. }
  30044. }
  30045. }
  30046. public function getCompletionType(): string
  30047. {
  30048. return $this->completionType;
  30049. }
  30050. public function getCompletionName(): ?string
  30051. {
  30052. return $this->completionName;
  30053. }
  30054. public function getCompletionValue(): string
  30055. {
  30056. return $this->completionValue;
  30057. }
  30058. public function mustSuggestOptionValuesFor(string $optionName): bool
  30059. {
  30060. return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName();
  30061. }
  30062. public function mustSuggestArgumentValuesFor(string $argumentName): bool
  30063. {
  30064. return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName();
  30065. }
  30066. protected function parseToken(string $token, bool $parseOptions): bool
  30067. {
  30068. try {
  30069. return parent::parseToken($token, $parseOptions);
  30070. } catch (RuntimeException $e) {
  30071. }
  30072. return $parseOptions;
  30073. }
  30074. private function getOptionFromToken(string $optionToken): ?InputOption
  30075. {
  30076. $optionName = ltrim($optionToken, '-');
  30077. if (!$optionName) {
  30078. return null;
  30079. }
  30080. if ('-' === ($optionToken[1] ?? ' ')) {
  30081. return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null;
  30082. }
  30083. return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null;
  30084. }
  30085. private function getRelevantToken(): string
  30086. {
  30087. return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex];
  30088. }
  30089. private function isCursorFree(): bool
  30090. {
  30091. $nrOfTokens = \count($this->tokens);
  30092. if ($this->currentIndex > $nrOfTokens) {
  30093. throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.');
  30094. }
  30095. return $this->currentIndex >= $nrOfTokens;
  30096. }
  30097. public function __toString()
  30098. {
  30099. $str = '';
  30100. foreach ($this->tokens as $i => $token) {
  30101. $str .= $token;
  30102. if ($this->currentIndex === $i) {
  30103. $str .= '|';
  30104. }
  30105. $str .= ' ';
  30106. }
  30107. if ($this->currentIndex > $i) {
  30108. $str .= '|';
  30109. }
  30110. return rtrim($str);
  30111. }
  30112. }
  30113. <?php
  30114. namespace Symfony\Component\Console\Style;
  30115. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  30116. use Symfony\Component\Console\Helper\ProgressBar;
  30117. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  30118. use Symfony\Component\Console\Output\OutputInterface;
  30119. abstract class OutputStyle implements OutputInterface, StyleInterface
  30120. {
  30121. private $output;
  30122. public function __construct(OutputInterface $output)
  30123. {
  30124. $this->output = $output;
  30125. }
  30126. public function newLine(int $count = 1)
  30127. {
  30128. $this->output->write(str_repeat(\PHP_EOL, $count));
  30129. }
  30130. public function createProgressBar(int $max = 0)
  30131. {
  30132. return new ProgressBar($this->output, $max);
  30133. }
  30134. public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
  30135. {
  30136. $this->output->write($messages, $newline, $type);
  30137. }
  30138. public function writeln($messages, int $type = self::OUTPUT_NORMAL)
  30139. {
  30140. $this->output->writeln($messages, $type);
  30141. }
  30142. public function setVerbosity(int $level)
  30143. {
  30144. $this->output->setVerbosity($level);
  30145. }
  30146. public function getVerbosity()
  30147. {
  30148. return $this->output->getVerbosity();
  30149. }
  30150. public function setDecorated(bool $decorated)
  30151. {
  30152. $this->output->setDecorated($decorated);
  30153. }
  30154. public function isDecorated()
  30155. {
  30156. return $this->output->isDecorated();
  30157. }
  30158. public function setFormatter(OutputFormatterInterface $formatter)
  30159. {
  30160. $this->output->setFormatter($formatter);
  30161. }
  30162. public function getFormatter()
  30163. {
  30164. return $this->output->getFormatter();
  30165. }
  30166. public function isQuiet()
  30167. {
  30168. return $this->output->isQuiet();
  30169. }
  30170. public function isVerbose()
  30171. {
  30172. return $this->output->isVerbose();
  30173. }
  30174. public function isVeryVerbose()
  30175. {
  30176. return $this->output->isVeryVerbose();
  30177. }
  30178. public function isDebug()
  30179. {
  30180. return $this->output->isDebug();
  30181. }
  30182. protected function getErrorOutput()
  30183. {
  30184. if (!$this->output instanceof ConsoleOutputInterface) {
  30185. return $this->output;
  30186. }
  30187. return $this->output->getErrorOutput();
  30188. }
  30189. }
  30190. <?php
  30191. namespace Symfony\Component\Console\Style;
  30192. use Symfony\Component\Console\Exception\InvalidArgumentException;
  30193. use Symfony\Component\Console\Exception\RuntimeException;
  30194. use Symfony\Component\Console\Formatter\OutputFormatter;
  30195. use Symfony\Component\Console\Helper\Helper;
  30196. use Symfony\Component\Console\Helper\ProgressBar;
  30197. use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
  30198. use Symfony\Component\Console\Helper\Table;
  30199. use Symfony\Component\Console\Helper\TableCell;
  30200. use Symfony\Component\Console\Helper\TableSeparator;
  30201. use Symfony\Component\Console\Input\InputInterface;
  30202. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  30203. use Symfony\Component\Console\Output\OutputInterface;
  30204. use Symfony\Component\Console\Output\TrimmedBufferOutput;
  30205. use Symfony\Component\Console\Question\ChoiceQuestion;
  30206. use Symfony\Component\Console\Question\ConfirmationQuestion;
  30207. use Symfony\Component\Console\Question\Question;
  30208. use Symfony\Component\Console\Terminal;
  30209. class SymfonyStyle extends OutputStyle
  30210. {
  30211. public const MAX_LINE_LENGTH = 120;
  30212. private $input;
  30213. private $output;
  30214. private $questionHelper;
  30215. private $progressBar;
  30216. private $lineLength;
  30217. private $bufferedOutput;
  30218. public function __construct(InputInterface $input, OutputInterface $output)
  30219. {
  30220. $this->input = $input;
  30221. $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());
  30222. $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
  30223. $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
  30224. parent::__construct($this->output = $output);
  30225. }
  30226. public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
  30227. {
  30228. $messages = \is_array($messages) ? array_values($messages) : [$messages];
  30229. $this->autoPrependBlock();
  30230. $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
  30231. $this->newLine();
  30232. }
  30233. public function title(string $message)
  30234. {
  30235. $this->autoPrependBlock();
  30236. $this->writeln([
  30237. sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
  30238. sprintf('<comment>%s</>', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
  30239. ]);
  30240. $this->newLine();
  30241. }
  30242. public function section(string $message)
  30243. {
  30244. $this->autoPrependBlock();
  30245. $this->writeln([
  30246. sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
  30247. sprintf('<comment>%s</>', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
  30248. ]);
  30249. $this->newLine();
  30250. }
  30251. public function listing(array $elements)
  30252. {
  30253. $this->autoPrependText();
  30254. $elements = array_map(function ($element) {
  30255. return sprintf(' * %s', $element);
  30256. }, $elements);
  30257. $this->writeln($elements);
  30258. $this->newLine();
  30259. }
  30260. public function text($message)
  30261. {
  30262. $this->autoPrependText();
  30263. $messages = \is_array($message) ? array_values($message) : [$message];
  30264. foreach ($messages as $message) {
  30265. $this->writeln(sprintf(' %s', $message));
  30266. }
  30267. }
  30268. public function comment($message)
  30269. {
  30270. $this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);
  30271. }
  30272. public function success($message)
  30273. {
  30274. $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
  30275. }
  30276. public function error($message)
  30277. {
  30278. $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
  30279. }
  30280. public function warning($message)
  30281. {
  30282. $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);
  30283. }
  30284. public function note($message)
  30285. {
  30286. $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
  30287. }
  30288. public function info($message)
  30289. {
  30290. $this->block($message, 'INFO', 'fg=green', ' ', true);
  30291. }
  30292. public function caution($message)
  30293. {
  30294. $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
  30295. }
  30296. public function table(array $headers, array $rows)
  30297. {
  30298. $this->createTable()
  30299. ->setHeaders($headers)
  30300. ->setRows($rows)
  30301. ->render()
  30302. ;
  30303. $this->newLine();
  30304. }
  30305. public function horizontalTable(array $headers, array $rows)
  30306. {
  30307. $this->createTable()
  30308. ->setHorizontal(true)
  30309. ->setHeaders($headers)
  30310. ->setRows($rows)
  30311. ->render()
  30312. ;
  30313. $this->newLine();
  30314. }
  30315. public function definitionList(...$list)
  30316. {
  30317. $headers = [];
  30318. $row = [];
  30319. foreach ($list as $value) {
  30320. if ($value instanceof TableSeparator) {
  30321. $headers[] = $value;
  30322. $row[] = $value;
  30323. continue;
  30324. }
  30325. if (\is_string($value)) {
  30326. $headers[] = new TableCell($value, ['colspan' => 2]);
  30327. $row[] = null;
  30328. continue;
  30329. }
  30330. if (!\is_array($value)) {
  30331. throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
  30332. }
  30333. $headers[] = key($value);
  30334. $row[] = current($value);
  30335. }
  30336. $this->horizontalTable($headers, [$row]);
  30337. }
  30338. public function ask(string $question, ?string $default = null, ?callable $validator = null)
  30339. {
  30340. $question = new Question($question, $default);
  30341. $question->setValidator($validator);
  30342. return $this->askQuestion($question);
  30343. }
  30344. public function askHidden(string $question, ?callable $validator = null)
  30345. {
  30346. $question = new Question($question);
  30347. $question->setHidden(true);
  30348. $question->setValidator($validator);
  30349. return $this->askQuestion($question);
  30350. }
  30351. public function confirm(string $question, bool $default = true)
  30352. {
  30353. return $this->askQuestion(new ConfirmationQuestion($question, $default));
  30354. }
  30355. public function choice(string $question, array $choices, $default = null)
  30356. {
  30357. if (null !== $default) {
  30358. $values = array_flip($choices);
  30359. $default = $values[$default] ?? $default;
  30360. }
  30361. return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
  30362. }
  30363. public function progressStart(int $max = 0)
  30364. {
  30365. $this->progressBar = $this->createProgressBar($max);
  30366. $this->progressBar->start();
  30367. }
  30368. public function progressAdvance(int $step = 1)
  30369. {
  30370. $this->getProgressBar()->advance($step);
  30371. }
  30372. public function progressFinish()
  30373. {
  30374. $this->getProgressBar()->finish();
  30375. $this->newLine(2);
  30376. $this->progressBar = null;
  30377. }
  30378. public function createProgressBar(int $max = 0)
  30379. {
  30380. $progressBar = parent::createProgressBar($max);
  30381. if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
  30382. $progressBar->setEmptyBarCharacter('â–‘');
  30383. $progressBar->setProgressCharacter('');
  30384. $progressBar->setBarCharacter('â–“');
  30385. }
  30386. return $progressBar;
  30387. }
  30388. public function progressIterate(iterable $iterable, ?int $max = null): iterable
  30389. {
  30390. yield from $this->createProgressBar()->iterate($iterable, $max);
  30391. $this->newLine(2);
  30392. }
  30393. public function askQuestion(Question $question)
  30394. {
  30395. if ($this->input->isInteractive()) {
  30396. $this->autoPrependBlock();
  30397. }
  30398. if (!$this->questionHelper) {
  30399. $this->questionHelper = new SymfonyQuestionHelper();
  30400. }
  30401. $answer = $this->questionHelper->ask($this->input, $this, $question);
  30402. if ($this->input->isInteractive()) {
  30403. $this->newLine();
  30404. $this->bufferedOutput->write("\n");
  30405. }
  30406. return $answer;
  30407. }
  30408. public function writeln($messages, int $type = self::OUTPUT_NORMAL)
  30409. {
  30410. if (!is_iterable($messages)) {
  30411. $messages = [$messages];
  30412. }
  30413. foreach ($messages as $message) {
  30414. parent::writeln($message, $type);
  30415. $this->writeBuffer($message, true, $type);
  30416. }
  30417. }
  30418. public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
  30419. {
  30420. if (!is_iterable($messages)) {
  30421. $messages = [$messages];
  30422. }
  30423. foreach ($messages as $message) {
  30424. parent::write($message, $newline, $type);
  30425. $this->writeBuffer($message, $newline, $type);
  30426. }
  30427. }
  30428. public function newLine(int $count = 1)
  30429. {
  30430. parent::newLine($count);
  30431. $this->bufferedOutput->write(str_repeat("\n", $count));
  30432. }
  30433. public function getErrorStyle()
  30434. {
  30435. return new self($this->input, $this->getErrorOutput());
  30436. }
  30437. public function createTable(): Table
  30438. {
  30439. $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output;
  30440. $style = clone Table::getStyleDefinition('symfony-style-guide');
  30441. $style->setCellHeaderFormat('<info>%s</info>');
  30442. return (new Table($output))->setStyle($style);
  30443. }
  30444. private function getProgressBar(): ProgressBar
  30445. {
  30446. if (!$this->progressBar) {
  30447. throw new RuntimeException('The ProgressBar is not started.');
  30448. }
  30449. return $this->progressBar;
  30450. }
  30451. private function autoPrependBlock(): void
  30452. {
  30453. $chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
  30454. if (!isset($chars[0])) {
  30455. $this->newLine();
  30456. return;
  30457. }
  30458. $this->newLine(2 - substr_count($chars, "\n"));
  30459. }
  30460. private function autoPrependText(): void
  30461. {
  30462. $fetched = $this->bufferedOutput->fetch();
  30463. if (!str_ends_with($fetched, "\n")) {
  30464. $this->newLine();
  30465. }
  30466. }
  30467. private function writeBuffer(string $message, bool $newLine, int $type): void
  30468. {
  30469. $this->bufferedOutput->write($message, $newLine, $type);
  30470. }
  30471. private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
  30472. {
  30473. $indentLength = 0;
  30474. $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));
  30475. $lines = [];
  30476. if (null !== $type) {
  30477. $type = sprintf('[%s] ', $type);
  30478. $indentLength = \strlen($type);
  30479. $lineIndentation = str_repeat(' ', $indentLength);
  30480. }
  30481. foreach ($messages as $key => $message) {
  30482. if ($escape) {
  30483. $message = OutputFormatter::escape($message);
  30484. }
  30485. $decorationLength = Helper::width($message) - Helper::width(Helper::removeDecoration($this->getFormatter(), $message));
  30486. $messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
  30487. $messageLines = explode(\PHP_EOL, wordwrap($message, $messageLineLength, \PHP_EOL, true));
  30488. foreach ($messageLines as $messageLine) {
  30489. $lines[] = $messageLine;
  30490. }
  30491. if (\count($messages) > 1 && $key < \count($messages) - 1) {
  30492. $lines[] = '';
  30493. }
  30494. }
  30495. $firstLineIndex = 0;
  30496. if ($padding && $this->isDecorated()) {
  30497. $firstLineIndex = 1;
  30498. array_unshift($lines, '');
  30499. $lines[] = '';
  30500. }
  30501. foreach ($lines as $i => &$line) {
  30502. if (null !== $type) {
  30503. $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
  30504. }
  30505. $line = $prefix.$line;
  30506. $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0));
  30507. if ($style) {
  30508. $line = sprintf('<%s>%s</>', $style, $line);
  30509. }
  30510. }
  30511. return $lines;
  30512. }
  30513. }
  30514. <?php
  30515. namespace Symfony\Component\Console\Style;
  30516. interface StyleInterface
  30517. {
  30518. public function title(string $message);
  30519. public function section(string $message);
  30520. public function listing(array $elements);
  30521. public function text($message);
  30522. public function success($message);
  30523. public function error($message);
  30524. public function warning($message);
  30525. public function note($message);
  30526. public function caution($message);
  30527. public function table(array $headers, array $rows);
  30528. public function ask(string $question, ?string $default = null, ?callable $validator = null);
  30529. public function askHidden(string $question, ?callable $validator = null);
  30530. public function confirm(string $question, bool $default = true);
  30531. public function choice(string $question, array $choices, $default = null);
  30532. public function newLine(int $count = 1);
  30533. public function progressStart(int $max = 0);
  30534. public function progressAdvance(int $step = 1);
  30535. public function progressFinish();
  30536. }
  30537. <?php
  30538. namespace Symfony\Component\Console\Question;
  30539. use Symfony\Component\Console\Exception\InvalidArgumentException;
  30540. class ChoiceQuestion extends Question
  30541. {
  30542. private $choices;
  30543. private $multiselect = false;
  30544. private $prompt = ' > ';
  30545. private $errorMessage = 'Value "%s" is invalid';
  30546. public function __construct(string $question, array $choices, $default = null)
  30547. {
  30548. if (!$choices) {
  30549. throw new \LogicException('Choice question must have at least 1 choice available.');
  30550. }
  30551. parent::__construct($question, $default);
  30552. $this->choices = $choices;
  30553. $this->setValidator($this->getDefaultValidator());
  30554. $this->setAutocompleterValues($choices);
  30555. }
  30556. public function getChoices()
  30557. {
  30558. return $this->choices;
  30559. }
  30560. public function setMultiselect(bool $multiselect)
  30561. {
  30562. $this->multiselect = $multiselect;
  30563. $this->setValidator($this->getDefaultValidator());
  30564. return $this;
  30565. }
  30566. public function isMultiselect()
  30567. {
  30568. return $this->multiselect;
  30569. }
  30570. public function getPrompt()
  30571. {
  30572. return $this->prompt;
  30573. }
  30574. public function setPrompt(string $prompt)
  30575. {
  30576. $this->prompt = $prompt;
  30577. return $this;
  30578. }
  30579. public function setErrorMessage(string $errorMessage)
  30580. {
  30581. $this->errorMessage = $errorMessage;
  30582. $this->setValidator($this->getDefaultValidator());
  30583. return $this;
  30584. }
  30585. private function getDefaultValidator(): callable
  30586. {
  30587. $choices = $this->choices;
  30588. $errorMessage = $this->errorMessage;
  30589. $multiselect = $this->multiselect;
  30590. $isAssoc = $this->isAssoc($choices);
  30591. return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
  30592. if ($multiselect) {
  30593. if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) {
  30594. throw new InvalidArgumentException(sprintf($errorMessage, $selected));
  30595. }
  30596. $selectedChoices = explode(',', (string) $selected);
  30597. } else {
  30598. $selectedChoices = [$selected];
  30599. }
  30600. if ($this->isTrimmable()) {
  30601. foreach ($selectedChoices as $k => $v) {
  30602. $selectedChoices[$k] = trim((string) $v);
  30603. }
  30604. }
  30605. $multiselectChoices = [];
  30606. foreach ($selectedChoices as $value) {
  30607. $results = [];
  30608. foreach ($choices as $key => $choice) {
  30609. if ($choice === $value) {
  30610. $results[] = $key;
  30611. }
  30612. }
  30613. if (\count($results) > 1) {
  30614. throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results)));
  30615. }
  30616. $result = array_search($value, $choices);
  30617. if (!$isAssoc) {
  30618. if (false !== $result) {
  30619. $result = $choices[$result];
  30620. } elseif (isset($choices[$value])) {
  30621. $result = $choices[$value];
  30622. }
  30623. } elseif (false === $result && isset($choices[$value])) {
  30624. $result = $value;
  30625. }
  30626. if (false === $result) {
  30627. throw new InvalidArgumentException(sprintf($errorMessage, $value));
  30628. }
  30629. $multiselectChoices[] = $isAssoc ? (string) $result : $result;
  30630. }
  30631. if ($multiselect) {
  30632. return $multiselectChoices;
  30633. }
  30634. return current($multiselectChoices);
  30635. };
  30636. }
  30637. }
  30638. <?php
  30639. namespace Symfony\Component\Console\Question;
  30640. use Symfony\Component\Console\Exception\InvalidArgumentException;
  30641. use Symfony\Component\Console\Exception\LogicException;
  30642. class Question
  30643. {
  30644. private $question;
  30645. private $attempts;
  30646. private $hidden = false;
  30647. private $hiddenFallback = true;
  30648. private $autocompleterCallback;
  30649. private $validator;
  30650. private $default;
  30651. private $normalizer;
  30652. private $trimmable = true;
  30653. private $multiline = false;
  30654. public function __construct(string $question, $default = null)
  30655. {
  30656. $this->question = $question;
  30657. $this->default = $default;
  30658. }
  30659. public function getQuestion()
  30660. {
  30661. return $this->question;
  30662. }
  30663. public function getDefault()
  30664. {
  30665. return $this->default;
  30666. }
  30667. public function isMultiline(): bool
  30668. {
  30669. return $this->multiline;
  30670. }
  30671. public function setMultiline(bool $multiline): self
  30672. {
  30673. $this->multiline = $multiline;
  30674. return $this;
  30675. }
  30676. public function isHidden()
  30677. {
  30678. return $this->hidden;
  30679. }
  30680. public function setHidden(bool $hidden)
  30681. {
  30682. if ($this->autocompleterCallback) {
  30683. throw new LogicException('A hidden question cannot use the autocompleter.');
  30684. }
  30685. $this->hidden = $hidden;
  30686. return $this;
  30687. }
  30688. public function isHiddenFallback()
  30689. {
  30690. return $this->hiddenFallback;
  30691. }
  30692. public function setHiddenFallback(bool $fallback)
  30693. {
  30694. $this->hiddenFallback = $fallback;
  30695. return $this;
  30696. }
  30697. public function getAutocompleterValues()
  30698. {
  30699. $callback = $this->getAutocompleterCallback();
  30700. return $callback ? $callback('') : null;
  30701. }
  30702. public function setAutocompleterValues(?iterable $values)
  30703. {
  30704. if (\is_array($values)) {
  30705. $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
  30706. $callback = static function () use ($values) {
  30707. return $values;
  30708. };
  30709. } elseif ($values instanceof \Traversable) {
  30710. $valueCache = null;
  30711. $callback = static function () use ($values, &$valueCache) {
  30712. return $valueCache ?? $valueCache = iterator_to_array($values, false);
  30713. };
  30714. } else {
  30715. $callback = null;
  30716. }
  30717. return $this->setAutocompleterCallback($callback);
  30718. }
  30719. public function getAutocompleterCallback(): ?callable
  30720. {
  30721. return $this->autocompleterCallback;
  30722. }
  30723. public function setAutocompleterCallback(?callable $callback = null): self
  30724. {
  30725. if ($this->hidden && null !== $callback) {
  30726. throw new LogicException('A hidden question cannot use the autocompleter.');
  30727. }
  30728. $this->autocompleterCallback = $callback;
  30729. return $this;
  30730. }
  30731. public function setValidator(?callable $validator = null)
  30732. {
  30733. $this->validator = $validator;
  30734. return $this;
  30735. }
  30736. public function getValidator()
  30737. {
  30738. return $this->validator;
  30739. }
  30740. public function setMaxAttempts(?int $attempts)
  30741. {
  30742. if (null !== $attempts && $attempts < 1) {
  30743. throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
  30744. }
  30745. $this->attempts = $attempts;
  30746. return $this;
  30747. }
  30748. public function getMaxAttempts()
  30749. {
  30750. return $this->attempts;
  30751. }
  30752. public function setNormalizer(callable $normalizer)
  30753. {
  30754. $this->normalizer = $normalizer;
  30755. return $this;
  30756. }
  30757. public function getNormalizer()
  30758. {
  30759. return $this->normalizer;
  30760. }
  30761. protected function isAssoc(array $array)
  30762. {
  30763. return (bool) \count(array_filter(array_keys($array), 'is_string'));
  30764. }
  30765. public function isTrimmable(): bool
  30766. {
  30767. return $this->trimmable;
  30768. }
  30769. public function setTrimmable(bool $trimmable): self
  30770. {
  30771. $this->trimmable = $trimmable;
  30772. return $this;
  30773. }
  30774. }
  30775. <?php
  30776. namespace Symfony\Component\Console\Question;
  30777. class ConfirmationQuestion extends Question
  30778. {
  30779. private $trueAnswerRegex;
  30780. public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i')
  30781. {
  30782. parent::__construct($question, $default);
  30783. $this->trueAnswerRegex = $trueAnswerRegex;
  30784. $this->setNormalizer($this->getDefaultNormalizer());
  30785. }
  30786. private function getDefaultNormalizer(): callable
  30787. {
  30788. $default = $this->getDefault();
  30789. $regex = $this->trueAnswerRegex;
  30790. return function ($answer) use ($default, $regex) {
  30791. if (\is_bool($answer)) {
  30792. return $answer;
  30793. }
  30794. $answerIsTrue = (bool) preg_match($regex, $answer);
  30795. if (false === $default) {
  30796. return $answer && $answerIsTrue;
  30797. }
  30798. return '' === $answer || $answerIsTrue;
  30799. };
  30800. }
  30801. }
  30802. <?php
  30803. namespace Symfony\Component\Console\Formatter;
  30804. use Symfony\Component\Console\Color;
  30805. class OutputFormatterStyle implements OutputFormatterStyleInterface
  30806. {
  30807. private $color;
  30808. private $foreground;
  30809. private $background;
  30810. private $options;
  30811. private $href;
  30812. private $handlesHrefGracefully;
  30813. public function __construct(?string $foreground = null, ?string $background = null, array $options = [])
  30814. {
  30815. $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
  30816. }
  30817. public function setForeground(?string $color = null)
  30818. {
  30819. $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
  30820. }
  30821. public function setBackground(?string $color = null)
  30822. {
  30823. $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
  30824. }
  30825. public function setHref(string $url): void
  30826. {
  30827. $this->href = $url;
  30828. }
  30829. public function setOption(string $option)
  30830. {
  30831. $this->options[] = $option;
  30832. $this->color = new Color($this->foreground, $this->background, $this->options);
  30833. }
  30834. public function unsetOption(string $option)
  30835. {
  30836. $pos = array_search($option, $this->options);
  30837. if (false !== $pos) {
  30838. unset($this->options[$pos]);
  30839. }
  30840. $this->color = new Color($this->foreground, $this->background, $this->options);
  30841. }
  30842. public function setOptions(array $options)
  30843. {
  30844. $this->color = new Color($this->foreground, $this->background, $this->options = $options);
  30845. }
  30846. public function apply(string $text)
  30847. {
  30848. if (null === $this->handlesHrefGracefully) {
  30849. $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
  30850. && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100)
  30851. && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']);
  30852. }
  30853. if (null !== $this->href && $this->handlesHrefGracefully) {
  30854. $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";
  30855. }
  30856. return $this->color->apply($text);
  30857. }
  30858. }
  30859. <?php
  30860. namespace Symfony\Component\Console\Formatter;
  30861. interface OutputFormatterStyleInterface
  30862. {
  30863. public function setForeground(?string $color = null);
  30864. public function setBackground(?string $color = null);
  30865. public function setOption(string $option);
  30866. public function unsetOption(string $option);
  30867. public function setOptions(array $options);
  30868. public function apply(string $text);
  30869. }
  30870. <?php
  30871. namespace Symfony\Component\Console\Formatter;
  30872. final class NullOutputFormatterStyle implements OutputFormatterStyleInterface
  30873. {
  30874. public function apply(string $text): string
  30875. {
  30876. return $text;
  30877. }
  30878. public function setBackground(?string $color = null): void
  30879. {
  30880. }
  30881. public function setForeground(?string $color = null): void
  30882. {
  30883. }
  30884. public function setOption(string $option): void
  30885. {
  30886. }
  30887. public function setOptions(array $options): void
  30888. {
  30889. }
  30890. public function unsetOption(string $option): void
  30891. {
  30892. }
  30893. }
  30894. <?php
  30895. namespace Symfony\Component\Console\Formatter;
  30896. interface OutputFormatterInterface
  30897. {
  30898. public function setDecorated(bool $decorated);
  30899. public function isDecorated();
  30900. public function setStyle(string $name, OutputFormatterStyleInterface $style);
  30901. public function hasStyle(string $name);
  30902. public function getStyle(string $name);
  30903. public function format(?string $message);
  30904. }
  30905. <?php
  30906. namespace Symfony\Component\Console\Formatter;
  30907. use Symfony\Component\Console\Exception\InvalidArgumentException;
  30908. use function Symfony\Component\String\b;
  30909. class OutputFormatter implements WrappableOutputFormatterInterface
  30910. {
  30911. private $decorated;
  30912. private $styles = [];
  30913. private $styleStack;
  30914. public function __clone()
  30915. {
  30916. $this->styleStack = clone $this->styleStack;
  30917. foreach ($this->styles as $key => $value) {
  30918. $this->styles[$key] = clone $value;
  30919. }
  30920. }
  30921. public static function escape(string $text)
  30922. {
  30923. $text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
  30924. return self::escapeTrailingBackslash($text);
  30925. }
  30926. public static function escapeTrailingBackslash(string $text): string
  30927. {
  30928. if (str_ends_with($text, '\\')) {
  30929. $len = \strlen($text);
  30930. $text = rtrim($text, '\\');
  30931. $text = str_replace("\0", '', $text);
  30932. $text .= str_repeat("\0", $len - \strlen($text));
  30933. }
  30934. return $text;
  30935. }
  30936. public function __construct(bool $decorated = false, array $styles = [])
  30937. {
  30938. $this->decorated = $decorated;
  30939. $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
  30940. $this->setStyle('info', new OutputFormatterStyle('green'));
  30941. $this->setStyle('comment', new OutputFormatterStyle('yellow'));
  30942. $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
  30943. foreach ($styles as $name => $style) {
  30944. $this->setStyle($name, $style);
  30945. }
  30946. $this->styleStack = new OutputFormatterStyleStack();
  30947. }
  30948. public function setDecorated(bool $decorated)
  30949. {
  30950. $this->decorated = $decorated;
  30951. }
  30952. public function isDecorated()
  30953. {
  30954. return $this->decorated;
  30955. }
  30956. public function setStyle(string $name, OutputFormatterStyleInterface $style)
  30957. {
  30958. $this->styles[strtolower($name)] = $style;
  30959. }
  30960. public function hasStyle(string $name)
  30961. {
  30962. return isset($this->styles[strtolower($name)]);
  30963. }
  30964. public function getStyle(string $name)
  30965. {
  30966. if (!$this->hasStyle($name)) {
  30967. throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
  30968. }
  30969. return $this->styles[strtolower($name)];
  30970. }
  30971. public function format(?string $message)
  30972. {
  30973. return $this->formatAndWrap($message, 0);
  30974. }
  30975. public function formatAndWrap(?string $message, int $width)
  30976. {
  30977. if (null === $message) {
  30978. return '';
  30979. }
  30980. $offset = 0;
  30981. $output = '';
  30982. $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
  30983. $closeTagRegex = '[a-z][^<>]*+';
  30984. $currentLineLength = 0;
  30985. preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
  30986. foreach ($matches[0] as $i => $match) {
  30987. $pos = $match[1];
  30988. $text = $match[0];
  30989. if (0 != $pos && '\\' == $message[$pos - 1]) {
  30990. continue;
  30991. }
  30992. $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
  30993. $offset = $pos + \strlen($text);
  30994. if ($open = '/' != $text[1]) {
  30995. $tag = $matches[1][$i][0];
  30996. } else {
  30997. $tag = $matches[3][$i][0] ?? '';
  30998. }
  30999. if (!$open && !$tag) {
  31000. $this->styleStack->pop();
  31001. } elseif (null === $style = $this->createStyleFromString($tag)) {
  31002. $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
  31003. } elseif ($open) {
  31004. $this->styleStack->push($style);
  31005. } else {
  31006. $this->styleStack->pop($style);
  31007. }
  31008. }
  31009. $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength);
  31010. return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
  31011. }
  31012. public function getStyleStack()
  31013. {
  31014. return $this->styleStack;
  31015. }
  31016. private function createStyleFromString(string $string): ?OutputFormatterStyleInterface
  31017. {
  31018. if (isset($this->styles[$string])) {
  31019. return $this->styles[$string];
  31020. }
  31021. if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
  31022. return null;
  31023. }
  31024. $style = new OutputFormatterStyle();
  31025. foreach ($matches as $match) {
  31026. array_shift($match);
  31027. $match[0] = strtolower($match[0]);
  31028. if ('fg' == $match[0]) {
  31029. $style->setForeground(strtolower($match[1]));
  31030. } elseif ('bg' == $match[0]) {
  31031. $style->setBackground(strtolower($match[1]));
  31032. } elseif ('href' === $match[0]) {
  31033. $url = preg_replace('{\\\\([<>])}', '$1', $match[1]);
  31034. $style->setHref($url);
  31035. } elseif ('options' === $match[0]) {
  31036. preg_match_all('([^,;]+)', strtolower($match[1]), $options);
  31037. $options = array_shift($options);
  31038. foreach ($options as $option) {
  31039. $style->setOption($option);
  31040. }
  31041. } else {
  31042. return null;
  31043. }
  31044. }
  31045. return $style;
  31046. }
  31047. private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string
  31048. {
  31049. if ('' === $text) {
  31050. return '';
  31051. }
  31052. if (!$width) {
  31053. return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;
  31054. }
  31055. if (!$currentLineLength && '' !== $current) {
  31056. $text = ltrim($text);
  31057. }
  31058. if ($currentLineLength) {
  31059. $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n";
  31060. $text = substr($text, $i);
  31061. } else {
  31062. $prefix = '';
  31063. }
  31064. preg_match('~(\\n)$~', $text, $matches);
  31065. $text = $prefix.$this->addLineBreaks($text, $width);
  31066. $text = rtrim($text, "\n").($matches[1] ?? '');
  31067. if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
  31068. $text = "\n".$text;
  31069. }
  31070. $lines = explode("\n", $text);
  31071. foreach ($lines as $line) {
  31072. $currentLineLength += \strlen($line);
  31073. if ($width <= $currentLineLength) {
  31074. $currentLineLength = 0;
  31075. }
  31076. }
  31077. if ($this->isDecorated()) {
  31078. foreach ($lines as $i => $line) {
  31079. $lines[$i] = $this->styleStack->getCurrent()->apply($line);
  31080. }
  31081. }
  31082. return implode("\n", $lines);
  31083. }
  31084. private function addLineBreaks(string $text, int $width): string
  31085. {
  31086. $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';
  31087. return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
  31088. }
  31089. }
  31090. <?php
  31091. namespace Symfony\Component\Console\Formatter;
  31092. final class NullOutputFormatter implements OutputFormatterInterface
  31093. {
  31094. private $style;
  31095. public function format(?string $message): ?string
  31096. {
  31097. return null;
  31098. }
  31099. public function getStyle(string $name): OutputFormatterStyleInterface
  31100. {
  31101. return $this->style ?? $this->style = new NullOutputFormatterStyle();
  31102. }
  31103. public function hasStyle(string $name): bool
  31104. {
  31105. return false;
  31106. }
  31107. public function isDecorated(): bool
  31108. {
  31109. return false;
  31110. }
  31111. public function setDecorated(bool $decorated): void
  31112. {
  31113. }
  31114. public function setStyle(string $name, OutputFormatterStyleInterface $style): void
  31115. {
  31116. }
  31117. }
  31118. <?php
  31119. namespace Symfony\Component\Console\Formatter;
  31120. interface WrappableOutputFormatterInterface extends OutputFormatterInterface
  31121. {
  31122. public function formatAndWrap(?string $message, int $width);
  31123. }
  31124. <?php
  31125. namespace Symfony\Component\Console\Formatter;
  31126. use Symfony\Component\Console\Exception\InvalidArgumentException;
  31127. use Symfony\Contracts\Service\ResetInterface;
  31128. class OutputFormatterStyleStack implements ResetInterface
  31129. {
  31130. private $styles;
  31131. private $emptyStyle;
  31132. public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)
  31133. {
  31134. $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
  31135. $this->reset();
  31136. }
  31137. public function reset()
  31138. {
  31139. $this->styles = [];
  31140. }
  31141. public function push(OutputFormatterStyleInterface $style)
  31142. {
  31143. $this->styles[] = $style;
  31144. }
  31145. public function pop(?OutputFormatterStyleInterface $style = null)
  31146. {
  31147. if (empty($this->styles)) {
  31148. return $this->emptyStyle;
  31149. }
  31150. if (null === $style) {
  31151. return array_pop($this->styles);
  31152. }
  31153. foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
  31154. if ($style->apply('') === $stackedStyle->apply('')) {
  31155. $this->styles = \array_slice($this->styles, 0, $index);
  31156. return $stackedStyle;
  31157. }
  31158. }
  31159. throw new InvalidArgumentException('Incorrectly nested style tag found.');
  31160. }
  31161. public function getCurrent()
  31162. {
  31163. if (empty($this->styles)) {
  31164. return $this->emptyStyle;
  31165. }
  31166. return $this->styles[\count($this->styles) - 1];
  31167. }
  31168. public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
  31169. {
  31170. $this->emptyStyle = $emptyStyle;
  31171. return $this;
  31172. }
  31173. public function getEmptyStyle()
  31174. {
  31175. return $this->emptyStyle;
  31176. }
  31177. }
  31178. <?php
  31179. namespace Symfony\Component\Console;
  31180. use Symfony\Component\Console\Exception\InvalidArgumentException;
  31181. final class Color
  31182. {
  31183. private const COLORS = [
  31184. 'black' => 0,
  31185. 'red' => 1,
  31186. 'green' => 2,
  31187. 'yellow' => 3,
  31188. 'blue' => 4,
  31189. 'magenta' => 5,
  31190. 'cyan' => 6,
  31191. 'white' => 7,
  31192. 'default' => 9,
  31193. ];
  31194. private const BRIGHT_COLORS = [
  31195. 'gray' => 0,
  31196. 'bright-red' => 1,
  31197. 'bright-green' => 2,
  31198. 'bright-yellow' => 3,
  31199. 'bright-blue' => 4,
  31200. 'bright-magenta' => 5,
  31201. 'bright-cyan' => 6,
  31202. 'bright-white' => 7,
  31203. ];
  31204. private const AVAILABLE_OPTIONS = [
  31205. 'bold' => ['set' => 1, 'unset' => 22],
  31206. 'underscore' => ['set' => 4, 'unset' => 24],
  31207. 'blink' => ['set' => 5, 'unset' => 25],
  31208. 'reverse' => ['set' => 7, 'unset' => 27],
  31209. 'conceal' => ['set' => 8, 'unset' => 28],
  31210. ];
  31211. private $foreground;
  31212. private $background;
  31213. private $options = [];
  31214. public function __construct(string $foreground = '', string $background = '', array $options = [])
  31215. {
  31216. $this->foreground = $this->parseColor($foreground);
  31217. $this->background = $this->parseColor($background, true);
  31218. foreach ($options as $option) {
  31219. if (!isset(self::AVAILABLE_OPTIONS[$option])) {
  31220. throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS))));
  31221. }
  31222. $this->options[$option] = self::AVAILABLE_OPTIONS[$option];
  31223. }
  31224. }
  31225. public function apply(string $text): string
  31226. {
  31227. return $this->set().$text.$this->unset();
  31228. }
  31229. public function set(): string
  31230. {
  31231. $setCodes = [];
  31232. if ('' !== $this->foreground) {
  31233. $setCodes[] = $this->foreground;
  31234. }
  31235. if ('' !== $this->background) {
  31236. $setCodes[] = $this->background;
  31237. }
  31238. foreach ($this->options as $option) {
  31239. $setCodes[] = $option['set'];
  31240. }
  31241. if (0 === \count($setCodes)) {
  31242. return '';
  31243. }
  31244. return sprintf("\033[%sm", implode(';', $setCodes));
  31245. }
  31246. public function unset(): string
  31247. {
  31248. $unsetCodes = [];
  31249. if ('' !== $this->foreground) {
  31250. $unsetCodes[] = 39;
  31251. }
  31252. if ('' !== $this->background) {
  31253. $unsetCodes[] = 49;
  31254. }
  31255. foreach ($this->options as $option) {
  31256. $unsetCodes[] = $option['unset'];
  31257. }
  31258. if (0 === \count($unsetCodes)) {
  31259. return '';
  31260. }
  31261. return sprintf("\033[%sm", implode(';', $unsetCodes));
  31262. }
  31263. private function parseColor(string $color, bool $background = false): string
  31264. {
  31265. if ('' === $color) {
  31266. return '';
  31267. }
  31268. if ('#' === $color[0]) {
  31269. $color = substr($color, 1);
  31270. if (3 === \strlen($color)) {
  31271. $color = $color[0].$color[0].$color[1].$color[1].$color[2].$color[2];
  31272. }
  31273. if (6 !== \strlen($color)) {
  31274. throw new InvalidArgumentException(sprintf('Invalid "%s" color.', $color));
  31275. }
  31276. return ($background ? '4' : '3').$this->convertHexColorToAnsi(hexdec($color));
  31277. }
  31278. if (isset(self::COLORS[$color])) {
  31279. return ($background ? '4' : '3').self::COLORS[$color];
  31280. }
  31281. if (isset(self::BRIGHT_COLORS[$color])) {
  31282. return ($background ? '10' : '9').self::BRIGHT_COLORS[$color];
  31283. }
  31284. throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS)))));
  31285. }
  31286. private function convertHexColorToAnsi(int $color): string
  31287. {
  31288. $r = ($color >> 16) & 255;
  31289. $g = ($color >> 8) & 255;
  31290. $b = $color & 255;
  31291. if ('truecolor' !== getenv('COLORTERM')) {
  31292. return (string) $this->degradeHexColorToAnsi($r, $g, $b);
  31293. }
  31294. return sprintf('8;2;%d;%d;%d', $r, $g, $b);
  31295. }
  31296. private function degradeHexColorToAnsi(int $r, int $g, int $b): int
  31297. {
  31298. if (0 === round($this->getSaturation($r, $g, $b) / 50)) {
  31299. return 0;
  31300. }
  31301. return (round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255);
  31302. }
  31303. private function getSaturation(int $r, int $g, int $b): int
  31304. {
  31305. $r = $r / 255;
  31306. $g = $g / 255;
  31307. $b = $b / 255;
  31308. $v = max($r, $g, $b);
  31309. if (0 === $diff = $v - min($r, $g, $b)) {
  31310. return 0;
  31311. }
  31312. return (int) $diff * 100 / $v;
  31313. }
  31314. }
  31315. <?php
  31316. namespace Symfony\Component\Console\SignalRegistry;
  31317. final class SignalRegistry
  31318. {
  31319. private $signalHandlers = [];
  31320. public function __construct()
  31321. {
  31322. if (\function_exists('pcntl_async_signals')) {
  31323. pcntl_async_signals(true);
  31324. }
  31325. }
  31326. public function register(int $signal, callable $signalHandler): void
  31327. {
  31328. if (!isset($this->signalHandlers[$signal])) {
  31329. $previousCallback = pcntl_signal_get_handler($signal);
  31330. if (\is_callable($previousCallback)) {
  31331. $this->signalHandlers[$signal][] = $previousCallback;
  31332. }
  31333. }
  31334. $this->signalHandlers[$signal][] = $signalHandler;
  31335. pcntl_signal($signal, [$this, 'handle']);
  31336. }
  31337. public static function isSupported(): bool
  31338. {
  31339. if (!\function_exists('pcntl_signal')) {
  31340. return false;
  31341. }
  31342. if (\in_array('pcntl_signal', explode(',', \ini_get('disable_functions')))) {
  31343. return false;
  31344. }
  31345. return true;
  31346. }
  31347. public function handle(int $signal): void
  31348. {
  31349. $count = \count($this->signalHandlers[$signal]);
  31350. foreach ($this->signalHandlers[$signal] as $i => $signalHandler) {
  31351. $hasNext = $i !== $count - 1;
  31352. $signalHandler($signal, $hasNext);
  31353. }
  31354. }
  31355. }
  31356. <?php
  31357. namespace Symfony\Component\Console;
  31358. use Symfony\Component\Console\Command\Command;
  31359. use Symfony\Component\Console\Input\InputInterface;
  31360. use Symfony\Component\Console\Output\OutputInterface;
  31361. class SingleCommandApplication extends Command
  31362. {
  31363. private $version = 'UNKNOWN';
  31364. private $autoExit = true;
  31365. private $running = false;
  31366. public function setVersion(string $version): self
  31367. {
  31368. $this->version = $version;
  31369. return $this;
  31370. }
  31371. public function setAutoExit(bool $autoExit): self
  31372. {
  31373. $this->autoExit = $autoExit;
  31374. return $this;
  31375. }
  31376. public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
  31377. {
  31378. if ($this->running) {
  31379. return parent::run($input, $output);
  31380. }
  31381. $application = new Application($this->getName() ?: 'UNKNOWN', $this->version);
  31382. $application->setAutoExit($this->autoExit);
  31383. $this->setName($_SERVER['argv'][0]);
  31384. $application->add($this);
  31385. $application->setDefaultCommand($this->getName(), true);
  31386. $this->running = true;
  31387. try {
  31388. $ret = $application->run($input, $output);
  31389. } finally {
  31390. $this->running = false;
  31391. }
  31392. return $ret ?? 1;
  31393. }
  31394. }
  31395. <?php
  31396. namespace Symfony\Component\Console\CommandLoader;
  31397. use Symfony\Component\Console\Command\Command;
  31398. use Symfony\Component\Console\Exception\CommandNotFoundException;
  31399. interface CommandLoaderInterface
  31400. {
  31401. public function get(string $name);
  31402. public function has(string $name);
  31403. public function getNames();
  31404. }
  31405. <?php
  31406. namespace Symfony\Component\Console\CommandLoader;
  31407. use Psr\Container\ContainerInterface;
  31408. use Symfony\Component\Console\Exception\CommandNotFoundException;
  31409. class ContainerCommandLoader implements CommandLoaderInterface
  31410. {
  31411. private $container;
  31412. private $commandMap;
  31413. public function __construct(ContainerInterface $container, array $commandMap)
  31414. {
  31415. $this->container = $container;
  31416. $this->commandMap = $commandMap;
  31417. }
  31418. public function get(string $name)
  31419. {
  31420. if (!$this->has($name)) {
  31421. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  31422. }
  31423. return $this->container->get($this->commandMap[$name]);
  31424. }
  31425. public function has(string $name)
  31426. {
  31427. return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
  31428. }
  31429. public function getNames()
  31430. {
  31431. return array_keys($this->commandMap);
  31432. }
  31433. }
  31434. <?php
  31435. namespace Symfony\Component\Console\CommandLoader;
  31436. use Symfony\Component\Console\Exception\CommandNotFoundException;
  31437. class FactoryCommandLoader implements CommandLoaderInterface
  31438. {
  31439. private $factories;
  31440. public function __construct(array $factories)
  31441. {
  31442. $this->factories = $factories;
  31443. }
  31444. public function has(string $name)
  31445. {
  31446. return isset($this->factories[$name]);
  31447. }
  31448. public function get(string $name)
  31449. {
  31450. if (!isset($this->factories[$name])) {
  31451. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  31452. }
  31453. $factory = $this->factories[$name];
  31454. return $factory();
  31455. }
  31456. public function getNames()
  31457. {
  31458. return array_keys($this->factories);
  31459. }
  31460. }
  31461. <?php
  31462. namespace Symfony\Component\Console\Descriptor;
  31463. use Symfony\Component\Console\Application;
  31464. use Symfony\Component\Console\Command\Command;
  31465. use Symfony\Component\Console\Formatter\OutputFormatter;
  31466. use Symfony\Component\Console\Helper\Helper;
  31467. use Symfony\Component\Console\Input\InputArgument;
  31468. use Symfony\Component\Console\Input\InputDefinition;
  31469. use Symfony\Component\Console\Input\InputOption;
  31470. class TextDescriptor extends Descriptor
  31471. {
  31472. protected function describeInputArgument(InputArgument $argument, array $options = [])
  31473. {
  31474. if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
  31475. $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
  31476. } else {
  31477. $default = '';
  31478. }
  31479. $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());
  31480. $spacingWidth = $totalWidth - \strlen($argument->getName());
  31481. $this->writeText(sprintf(' <info>%s</info> %s%s%s',
  31482. $argument->getName(),
  31483. str_repeat(' ', $spacingWidth),
  31484. preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
  31485. $default
  31486. ), $options);
  31487. }
  31488. protected function describeInputOption(InputOption $option, array $options = [])
  31489. {
  31490. if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
  31491. $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
  31492. } else {
  31493. $default = '';
  31494. }
  31495. $value = '';
  31496. if ($option->acceptValue()) {
  31497. $value = '='.strtoupper($option->getName());
  31498. if ($option->isValueOptional()) {
  31499. $value = '['.$value.']';
  31500. }
  31501. }
  31502. $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
  31503. $synopsis = sprintf('%s%s',
  31504. $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ',
  31505. sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)
  31506. );
  31507. $spacingWidth = $totalWidth - Helper::width($synopsis);
  31508. $this->writeText(sprintf(' <info>%s</info> %s%s%s%s',
  31509. $synopsis,
  31510. str_repeat(' ', $spacingWidth),
  31511. preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
  31512. $default,
  31513. $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
  31514. ), $options);
  31515. }
  31516. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  31517. {
  31518. $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
  31519. foreach ($definition->getArguments() as $argument) {
  31520. $totalWidth = max($totalWidth, Helper::width($argument->getName()));
  31521. }
  31522. if ($definition->getArguments()) {
  31523. $this->writeText('<comment>Arguments:</comment>', $options);
  31524. $this->writeText("\n");
  31525. foreach ($definition->getArguments() as $argument) {
  31526. $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
  31527. $this->writeText("\n");
  31528. }
  31529. }
  31530. if ($definition->getArguments() && $definition->getOptions()) {
  31531. $this->writeText("\n");
  31532. }
  31533. if ($definition->getOptions()) {
  31534. $laterOptions = [];
  31535. $this->writeText('<comment>Options:</comment>', $options);
  31536. foreach ($definition->getOptions() as $option) {
  31537. if (\strlen($option->getShortcut() ?? '') > 1) {
  31538. $laterOptions[] = $option;
  31539. continue;
  31540. }
  31541. $this->writeText("\n");
  31542. $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
  31543. }
  31544. foreach ($laterOptions as $option) {
  31545. $this->writeText("\n");
  31546. $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
  31547. }
  31548. }
  31549. }
  31550. protected function describeCommand(Command $command, array $options = [])
  31551. {
  31552. $command->mergeApplicationDefinition(false);
  31553. if ($description = $command->getDescription()) {
  31554. $this->writeText('<comment>Description:</comment>', $options);
  31555. $this->writeText("\n");
  31556. $this->writeText(' '.$description);
  31557. $this->writeText("\n\n");
  31558. }
  31559. $this->writeText('<comment>Usage:</comment>', $options);
  31560. foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
  31561. $this->writeText("\n");
  31562. $this->writeText(' '.OutputFormatter::escape($usage), $options);
  31563. }
  31564. $this->writeText("\n");
  31565. $definition = $command->getDefinition();
  31566. if ($definition->getOptions() || $definition->getArguments()) {
  31567. $this->writeText("\n");
  31568. $this->describeInputDefinition($definition, $options);
  31569. $this->writeText("\n");
  31570. }
  31571. $help = $command->getProcessedHelp();
  31572. if ($help && $help !== $description) {
  31573. $this->writeText("\n");
  31574. $this->writeText('<comment>Help:</comment>', $options);
  31575. $this->writeText("\n");
  31576. $this->writeText(' '.str_replace("\n", "\n ", $help), $options);
  31577. $this->writeText("\n");
  31578. }
  31579. }
  31580. protected function describeApplication(Application $application, array $options = [])
  31581. {
  31582. $describedNamespace = $options['namespace'] ?? null;
  31583. $description = new ApplicationDescription($application, $describedNamespace);
  31584. if (isset($options['raw_text']) && $options['raw_text']) {
  31585. $width = $this->getColumnWidth($description->getCommands());
  31586. foreach ($description->getCommands() as $command) {
  31587. $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
  31588. $this->writeText("\n");
  31589. }
  31590. } else {
  31591. if ('' != $help = $application->getHelp()) {
  31592. $this->writeText("$help\n\n", $options);
  31593. }
  31594. $this->writeText("<comment>Usage:</comment>\n", $options);
  31595. $this->writeText(" command [options] [arguments]\n\n", $options);
  31596. $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
  31597. $this->writeText("\n");
  31598. $this->writeText("\n");
  31599. $commands = $description->getCommands();
  31600. $namespaces = $description->getNamespaces();
  31601. if ($describedNamespace && $namespaces) {
  31602. $describedNamespaceInfo = reset($namespaces);
  31603. foreach ($describedNamespaceInfo['commands'] as $name) {
  31604. $commands[$name] = $description->getCommand($name);
  31605. }
  31606. }
  31607. $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {
  31608. return array_intersect($namespace['commands'], array_keys($commands));
  31609. }, array_values($namespaces)))));
  31610. if ($describedNamespace) {
  31611. $this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
  31612. } else {
  31613. $this->writeText('<comment>Available commands:</comment>', $options);
  31614. }
  31615. foreach ($namespaces as $namespace) {
  31616. $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {
  31617. return isset($commands[$name]);
  31618. });
  31619. if (!$namespace['commands']) {
  31620. continue;
  31621. }
  31622. if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
  31623. $this->writeText("\n");
  31624. $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
  31625. }
  31626. foreach ($namespace['commands'] as $name) {
  31627. $this->writeText("\n");
  31628. $spacingWidth = $width - Helper::width($name);
  31629. $command = $commands[$name];
  31630. $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
  31631. $this->writeText(sprintf(' <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
  31632. }
  31633. }
  31634. $this->writeText("\n");
  31635. }
  31636. }
  31637. private function writeText(string $content, array $options = [])
  31638. {
  31639. $this->write(
  31640. isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
  31641. isset($options['raw_output']) ? !$options['raw_output'] : true
  31642. );
  31643. }
  31644. private function getCommandAliasesText(Command $command): string
  31645. {
  31646. $text = '';
  31647. $aliases = $command->getAliases();
  31648. if ($aliases) {
  31649. $text = '['.implode('|', $aliases).'] ';
  31650. }
  31651. return $text;
  31652. }
  31653. private function formatDefaultValue($default): string
  31654. {
  31655. if (\INF === $default) {
  31656. return 'INF';
  31657. }
  31658. if (\is_string($default)) {
  31659. $default = OutputFormatter::escape($default);
  31660. } elseif (\is_array($default)) {
  31661. foreach ($default as $key => $value) {
  31662. if (\is_string($value)) {
  31663. $default[$key] = OutputFormatter::escape($value);
  31664. }
  31665. }
  31666. }
  31667. return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
  31668. }
  31669. private function getColumnWidth(array $commands): int
  31670. {
  31671. $widths = [];
  31672. foreach ($commands as $command) {
  31673. if ($command instanceof Command) {
  31674. $widths[] = Helper::width($command->getName());
  31675. foreach ($command->getAliases() as $alias) {
  31676. $widths[] = Helper::width($alias);
  31677. }
  31678. } else {
  31679. $widths[] = Helper::width($command);
  31680. }
  31681. }
  31682. return $widths ? max($widths) + 2 : 0;
  31683. }
  31684. private function calculateTotalWidthForOptions(array $options): int
  31685. {
  31686. $totalWidth = 0;
  31687. foreach ($options as $option) {
  31688. $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName());
  31689. if ($option->isNegatable()) {
  31690. $nameLength += 6 + Helper::width($option->getName());
  31691. } elseif ($option->acceptValue()) {
  31692. $valueLength = 1 + Helper::width($option->getName());
  31693. $valueLength += $option->isValueOptional() ? 2 : 0;
  31694. $nameLength += $valueLength;
  31695. }
  31696. $totalWidth = max($totalWidth, $nameLength);
  31697. }
  31698. return $totalWidth;
  31699. }
  31700. }
  31701. <?php
  31702. namespace Symfony\Component\Console\Descriptor;
  31703. use Symfony\Component\Console\Application;
  31704. use Symfony\Component\Console\Command\Command;
  31705. use Symfony\Component\Console\Exception\CommandNotFoundException;
  31706. class ApplicationDescription
  31707. {
  31708. public const GLOBAL_NAMESPACE = '_global';
  31709. private $application;
  31710. private $namespace;
  31711. private $showHidden;
  31712. private $namespaces;
  31713. private $commands;
  31714. private $aliases;
  31715. public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false)
  31716. {
  31717. $this->application = $application;
  31718. $this->namespace = $namespace;
  31719. $this->showHidden = $showHidden;
  31720. }
  31721. public function getNamespaces(): array
  31722. {
  31723. if (null === $this->namespaces) {
  31724. $this->inspectApplication();
  31725. }
  31726. return $this->namespaces;
  31727. }
  31728. public function getCommands(): array
  31729. {
  31730. if (null === $this->commands) {
  31731. $this->inspectApplication();
  31732. }
  31733. return $this->commands;
  31734. }
  31735. public function getCommand(string $name): Command
  31736. {
  31737. if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
  31738. throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
  31739. }
  31740. return $this->commands[$name] ?? $this->aliases[$name];
  31741. }
  31742. private function inspectApplication()
  31743. {
  31744. $this->commands = [];
  31745. $this->namespaces = [];
  31746. $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
  31747. foreach ($this->sortCommands($all) as $namespace => $commands) {
  31748. $names = [];
  31749. foreach ($commands as $name => $command) {
  31750. if (!$command->getName() || (!$this->showHidden && $command->isHidden())) {
  31751. continue;
  31752. }
  31753. if ($command->getName() === $name) {
  31754. $this->commands[$name] = $command;
  31755. } else {
  31756. $this->aliases[$name] = $command;
  31757. }
  31758. $names[] = $name;
  31759. }
  31760. $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
  31761. }
  31762. }
  31763. private function sortCommands(array $commands): array
  31764. {
  31765. $namespacedCommands = [];
  31766. $globalCommands = [];
  31767. $sortedCommands = [];
  31768. foreach ($commands as $name => $command) {
  31769. $key = $this->application->extractNamespace($name, 1);
  31770. if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {
  31771. $globalCommands[$name] = $command;
  31772. } else {
  31773. $namespacedCommands[$key][$name] = $command;
  31774. }
  31775. }
  31776. if ($globalCommands) {
  31777. ksort($globalCommands);
  31778. $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
  31779. }
  31780. if ($namespacedCommands) {
  31781. ksort($namespacedCommands, \SORT_STRING);
  31782. foreach ($namespacedCommands as $key => $commandsSet) {
  31783. ksort($commandsSet);
  31784. $sortedCommands[$key] = $commandsSet;
  31785. }
  31786. }
  31787. return $sortedCommands;
  31788. }
  31789. }
  31790. <?php
  31791. namespace Symfony\Component\Console\Descriptor;
  31792. use Symfony\Component\Console\Application;
  31793. use Symfony\Component\Console\Command\Command;
  31794. use Symfony\Component\Console\Input\InputArgument;
  31795. use Symfony\Component\Console\Input\InputDefinition;
  31796. use Symfony\Component\Console\Input\InputOption;
  31797. class XmlDescriptor extends Descriptor
  31798. {
  31799. public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument
  31800. {
  31801. $dom = new \DOMDocument('1.0', 'UTF-8');
  31802. $dom->appendChild($definitionXML = $dom->createElement('definition'));
  31803. $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
  31804. foreach ($definition->getArguments() as $argument) {
  31805. $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
  31806. }
  31807. $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
  31808. foreach ($definition->getOptions() as $option) {
  31809. $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
  31810. }
  31811. return $dom;
  31812. }
  31813. public function getCommandDocument(Command $command, bool $short = false): \DOMDocument
  31814. {
  31815. $dom = new \DOMDocument('1.0', 'UTF-8');
  31816. $dom->appendChild($commandXML = $dom->createElement('command'));
  31817. $commandXML->setAttribute('id', $command->getName());
  31818. $commandXML->setAttribute('name', $command->getName());
  31819. $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
  31820. $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
  31821. $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
  31822. $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
  31823. if ($short) {
  31824. foreach ($command->getAliases() as $usage) {
  31825. $usagesXML->appendChild($dom->createElement('usage', $usage));
  31826. }
  31827. } else {
  31828. $command->mergeApplicationDefinition(false);
  31829. foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
  31830. $usagesXML->appendChild($dom->createElement('usage', $usage));
  31831. }
  31832. $commandXML->appendChild($helpXML = $dom->createElement('help'));
  31833. $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
  31834. $definitionXML = $this->getInputDefinitionDocument($command->getDefinition());
  31835. $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
  31836. }
  31837. return $dom;
  31838. }
  31839. public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument
  31840. {
  31841. $dom = new \DOMDocument('1.0', 'UTF-8');
  31842. $dom->appendChild($rootXml = $dom->createElement('symfony'));
  31843. if ('UNKNOWN' !== $application->getName()) {
  31844. $rootXml->setAttribute('name', $application->getName());
  31845. if ('UNKNOWN' !== $application->getVersion()) {
  31846. $rootXml->setAttribute('version', $application->getVersion());
  31847. }
  31848. }
  31849. $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
  31850. $description = new ApplicationDescription($application, $namespace, true);
  31851. if ($namespace) {
  31852. $commandsXML->setAttribute('namespace', $namespace);
  31853. }
  31854. foreach ($description->getCommands() as $command) {
  31855. $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
  31856. }
  31857. if (!$namespace) {
  31858. $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
  31859. foreach ($description->getNamespaces() as $namespaceDescription) {
  31860. $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
  31861. $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
  31862. foreach ($namespaceDescription['commands'] as $name) {
  31863. $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
  31864. $commandXML->appendChild($dom->createTextNode($name));
  31865. }
  31866. }
  31867. }
  31868. return $dom;
  31869. }
  31870. protected function describeInputArgument(InputArgument $argument, array $options = [])
  31871. {
  31872. $this->writeDocument($this->getInputArgumentDocument($argument));
  31873. }
  31874. protected function describeInputOption(InputOption $option, array $options = [])
  31875. {
  31876. $this->writeDocument($this->getInputOptionDocument($option));
  31877. }
  31878. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  31879. {
  31880. $this->writeDocument($this->getInputDefinitionDocument($definition));
  31881. }
  31882. protected function describeCommand(Command $command, array $options = [])
  31883. {
  31884. $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
  31885. }
  31886. protected function describeApplication(Application $application, array $options = [])
  31887. {
  31888. $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));
  31889. }
  31890. private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
  31891. {
  31892. foreach ($importedParent->childNodes as $childNode) {
  31893. $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
  31894. }
  31895. }
  31896. private function writeDocument(\DOMDocument $dom)
  31897. {
  31898. $dom->formatOutput = true;
  31899. $this->write($dom->saveXML());
  31900. }
  31901. private function getInputArgumentDocument(InputArgument $argument): \DOMDocument
  31902. {
  31903. $dom = new \DOMDocument('1.0', 'UTF-8');
  31904. $dom->appendChild($objectXML = $dom->createElement('argument'));
  31905. $objectXML->setAttribute('name', $argument->getName());
  31906. $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
  31907. $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
  31908. $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
  31909. $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
  31910. $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
  31911. $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
  31912. foreach ($defaults as $default) {
  31913. $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
  31914. $defaultXML->appendChild($dom->createTextNode($default));
  31915. }
  31916. return $dom;
  31917. }
  31918. private function getInputOptionDocument(InputOption $option): \DOMDocument
  31919. {
  31920. $dom = new \DOMDocument('1.0', 'UTF-8');
  31921. $dom->appendChild($objectXML = $dom->createElement('option'));
  31922. $objectXML->setAttribute('name', '--'.$option->getName());
  31923. $pos = strpos($option->getShortcut() ?? '', '|');
  31924. if (false !== $pos) {
  31925. $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
  31926. $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
  31927. } else {
  31928. $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
  31929. }
  31930. $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
  31931. $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
  31932. $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
  31933. $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
  31934. $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
  31935. if ($option->acceptValue()) {
  31936. $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));
  31937. $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
  31938. if (!empty($defaults)) {
  31939. foreach ($defaults as $default) {
  31940. $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
  31941. $defaultXML->appendChild($dom->createTextNode($default));
  31942. }
  31943. }
  31944. }
  31945. if ($option->isNegatable()) {
  31946. $dom->appendChild($objectXML = $dom->createElement('option'));
  31947. $objectXML->setAttribute('name', '--no-'.$option->getName());
  31948. $objectXML->setAttribute('shortcut', '');
  31949. $objectXML->setAttribute('accept_value', 0);
  31950. $objectXML->setAttribute('is_value_required', 0);
  31951. $objectXML->setAttribute('is_multiple', 0);
  31952. $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
  31953. $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option'));
  31954. }
  31955. return $dom;
  31956. }
  31957. }
  31958. <?php
  31959. namespace Symfony\Component\Console\Descriptor;
  31960. use Symfony\Component\Console\Output\OutputInterface;
  31961. interface DescriptorInterface
  31962. {
  31963. public function describe(OutputInterface $output, object $object, array $options = []);
  31964. }
  31965. <?php
  31966. namespace Symfony\Component\Console\Descriptor;
  31967. use Symfony\Component\Console\Application;
  31968. use Symfony\Component\Console\Command\Command;
  31969. use Symfony\Component\Console\Exception\InvalidArgumentException;
  31970. use Symfony\Component\Console\Input\InputArgument;
  31971. use Symfony\Component\Console\Input\InputDefinition;
  31972. use Symfony\Component\Console\Input\InputOption;
  31973. use Symfony\Component\Console\Output\OutputInterface;
  31974. abstract class Descriptor implements DescriptorInterface
  31975. {
  31976. protected $output;
  31977. public function describe(OutputInterface $output, object $object, array $options = [])
  31978. {
  31979. $this->output = $output;
  31980. switch (true) {
  31981. case $object instanceof InputArgument:
  31982. $this->describeInputArgument($object, $options);
  31983. break;
  31984. case $object instanceof InputOption:
  31985. $this->describeInputOption($object, $options);
  31986. break;
  31987. case $object instanceof InputDefinition:
  31988. $this->describeInputDefinition($object, $options);
  31989. break;
  31990. case $object instanceof Command:
  31991. $this->describeCommand($object, $options);
  31992. break;
  31993. case $object instanceof Application:
  31994. $this->describeApplication($object, $options);
  31995. break;
  31996. default:
  31997. throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object)));
  31998. }
  31999. }
  32000. protected function write(string $content, bool $decorated = false)
  32001. {
  32002. $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
  32003. }
  32004. abstract protected function describeInputArgument(InputArgument $argument, array $options = []);
  32005. abstract protected function describeInputOption(InputOption $option, array $options = []);
  32006. abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);
  32007. abstract protected function describeCommand(Command $command, array $options = []);
  32008. abstract protected function describeApplication(Application $application, array $options = []);
  32009. }
  32010. <?php
  32011. namespace Symfony\Component\Console\Descriptor;
  32012. use Symfony\Component\Console\Application;
  32013. use Symfony\Component\Console\Command\Command;
  32014. use Symfony\Component\Console\Input\InputArgument;
  32015. use Symfony\Component\Console\Input\InputDefinition;
  32016. use Symfony\Component\Console\Input\InputOption;
  32017. class JsonDescriptor extends Descriptor
  32018. {
  32019. protected function describeInputArgument(InputArgument $argument, array $options = [])
  32020. {
  32021. $this->writeData($this->getInputArgumentData($argument), $options);
  32022. }
  32023. protected function describeInputOption(InputOption $option, array $options = [])
  32024. {
  32025. $this->writeData($this->getInputOptionData($option), $options);
  32026. if ($option->isNegatable()) {
  32027. $this->writeData($this->getInputOptionData($option, true), $options);
  32028. }
  32029. }
  32030. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  32031. {
  32032. $this->writeData($this->getInputDefinitionData($definition), $options);
  32033. }
  32034. protected function describeCommand(Command $command, array $options = [])
  32035. {
  32036. $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
  32037. }
  32038. protected function describeApplication(Application $application, array $options = [])
  32039. {
  32040. $describedNamespace = $options['namespace'] ?? null;
  32041. $description = new ApplicationDescription($application, $describedNamespace, true);
  32042. $commands = [];
  32043. foreach ($description->getCommands() as $command) {
  32044. $commands[] = $this->getCommandData($command, $options['short'] ?? false);
  32045. }
  32046. $data = [];
  32047. if ('UNKNOWN' !== $application->getName()) {
  32048. $data['application']['name'] = $application->getName();
  32049. if ('UNKNOWN' !== $application->getVersion()) {
  32050. $data['application']['version'] = $application->getVersion();
  32051. }
  32052. }
  32053. $data['commands'] = $commands;
  32054. if ($describedNamespace) {
  32055. $data['namespace'] = $describedNamespace;
  32056. } else {
  32057. $data['namespaces'] = array_values($description->getNamespaces());
  32058. }
  32059. $this->writeData($data, $options);
  32060. }
  32061. private function writeData(array $data, array $options)
  32062. {
  32063. $flags = $options['json_encoding'] ?? 0;
  32064. $this->write(json_encode($data, $flags));
  32065. }
  32066. private function getInputArgumentData(InputArgument $argument): array
  32067. {
  32068. return [
  32069. 'name' => $argument->getName(),
  32070. 'is_required' => $argument->isRequired(),
  32071. 'is_array' => $argument->isArray(),
  32072. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
  32073. 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
  32074. ];
  32075. }
  32076. private function getInputOptionData(InputOption $option, bool $negated = false): array
  32077. {
  32078. return $negated ? [
  32079. 'name' => '--no-'.$option->getName(),
  32080. 'shortcut' => '',
  32081. 'accept_value' => false,
  32082. 'is_value_required' => false,
  32083. 'is_multiple' => false,
  32084. 'description' => 'Negate the "--'.$option->getName().'" option',
  32085. 'default' => false,
  32086. ] : [
  32087. 'name' => '--'.$option->getName(),
  32088. 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
  32089. 'accept_value' => $option->acceptValue(),
  32090. 'is_value_required' => $option->isValueRequired(),
  32091. 'is_multiple' => $option->isArray(),
  32092. 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
  32093. 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(),
  32094. ];
  32095. }
  32096. private function getInputDefinitionData(InputDefinition $definition): array
  32097. {
  32098. $inputArguments = [];
  32099. foreach ($definition->getArguments() as $name => $argument) {
  32100. $inputArguments[$name] = $this->getInputArgumentData($argument);
  32101. }
  32102. $inputOptions = [];
  32103. foreach ($definition->getOptions() as $name => $option) {
  32104. $inputOptions[$name] = $this->getInputOptionData($option);
  32105. if ($option->isNegatable()) {
  32106. $inputOptions['no-'.$name] = $this->getInputOptionData($option, true);
  32107. }
  32108. }
  32109. return ['arguments' => $inputArguments, 'options' => $inputOptions];
  32110. }
  32111. private function getCommandData(Command $command, bool $short = false): array
  32112. {
  32113. $data = [
  32114. 'name' => $command->getName(),
  32115. 'description' => $command->getDescription(),
  32116. ];
  32117. if ($short) {
  32118. $data += [
  32119. 'usage' => $command->getAliases(),
  32120. ];
  32121. } else {
  32122. $command->mergeApplicationDefinition(false);
  32123. $data += [
  32124. 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
  32125. 'help' => $command->getProcessedHelp(),
  32126. 'definition' => $this->getInputDefinitionData($command->getDefinition()),
  32127. ];
  32128. }
  32129. $data['hidden'] = $command->isHidden();
  32130. return $data;
  32131. }
  32132. }
  32133. <?php
  32134. namespace Symfony\Component\Console\Descriptor;
  32135. use Symfony\Component\Console\Application;
  32136. use Symfony\Component\Console\Command\Command;
  32137. use Symfony\Component\Console\Helper\Helper;
  32138. use Symfony\Component\Console\Input\InputArgument;
  32139. use Symfony\Component\Console\Input\InputDefinition;
  32140. use Symfony\Component\Console\Input\InputOption;
  32141. use Symfony\Component\Console\Output\OutputInterface;
  32142. class MarkdownDescriptor extends Descriptor
  32143. {
  32144. public function describe(OutputInterface $output, object $object, array $options = [])
  32145. {
  32146. $decorated = $output->isDecorated();
  32147. $output->setDecorated(false);
  32148. parent::describe($output, $object, $options);
  32149. $output->setDecorated($decorated);
  32150. }
  32151. protected function write(string $content, bool $decorated = true)
  32152. {
  32153. parent::write($content, $decorated);
  32154. }
  32155. protected function describeInputArgument(InputArgument $argument, array $options = [])
  32156. {
  32157. $this->write(
  32158. '#### `'.($argument->getName() ?: '<none>')."`\n\n"
  32159. .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
  32160. .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
  32161. .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
  32162. .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
  32163. );
  32164. }
  32165. protected function describeInputOption(InputOption $option, array $options = [])
  32166. {
  32167. $name = '--'.$option->getName();
  32168. if ($option->isNegatable()) {
  32169. $name .= '|--no-'.$option->getName();
  32170. }
  32171. if ($option->getShortcut()) {
  32172. $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
  32173. }
  32174. $this->write(
  32175. '#### `'.$name.'`'."\n\n"
  32176. .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '')
  32177. .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
  32178. .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
  32179. .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
  32180. .'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no')."\n"
  32181. .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
  32182. );
  32183. }
  32184. protected function describeInputDefinition(InputDefinition $definition, array $options = [])
  32185. {
  32186. if ($showArguments = \count($definition->getArguments()) > 0) {
  32187. $this->write('### Arguments');
  32188. foreach ($definition->getArguments() as $argument) {
  32189. $this->write("\n\n");
  32190. if (null !== $describeInputArgument = $this->describeInputArgument($argument)) {
  32191. $this->write($describeInputArgument);
  32192. }
  32193. }
  32194. }
  32195. if (\count($definition->getOptions()) > 0) {
  32196. if ($showArguments) {
  32197. $this->write("\n\n");
  32198. }
  32199. $this->write('### Options');
  32200. foreach ($definition->getOptions() as $option) {
  32201. $this->write("\n\n");
  32202. if (null !== $describeInputOption = $this->describeInputOption($option)) {
  32203. $this->write($describeInputOption);
  32204. }
  32205. }
  32206. }
  32207. }
  32208. protected function describeCommand(Command $command, array $options = [])
  32209. {
  32210. if ($options['short'] ?? false) {
  32211. $this->write(
  32212. '`'.$command->getName()."`\n"
  32213. .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
  32214. .($command->getDescription() ? $command->getDescription()."\n\n" : '')
  32215. .'### Usage'."\n\n"
  32216. .array_reduce($command->getAliases(), function ($carry, $usage) {
  32217. return $carry.'* `'.$usage.'`'."\n";
  32218. })
  32219. );
  32220. return;
  32221. }
  32222. $command->mergeApplicationDefinition(false);
  32223. $this->write(
  32224. '`'.$command->getName()."`\n"
  32225. .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
  32226. .($command->getDescription() ? $command->getDescription()."\n\n" : '')
  32227. .'### Usage'."\n\n"
  32228. .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
  32229. return $carry.'* `'.$usage.'`'."\n";
  32230. })
  32231. );
  32232. if ($help = $command->getProcessedHelp()) {
  32233. $this->write("\n");
  32234. $this->write($help);
  32235. }
  32236. $definition = $command->getDefinition();
  32237. if ($definition->getOptions() || $definition->getArguments()) {
  32238. $this->write("\n\n");
  32239. $this->describeInputDefinition($definition);
  32240. }
  32241. }
  32242. protected function describeApplication(Application $application, array $options = [])
  32243. {
  32244. $describedNamespace = $options['namespace'] ?? null;
  32245. $description = new ApplicationDescription($application, $describedNamespace);
  32246. $title = $this->getApplicationTitle($application);
  32247. $this->write($title."\n".str_repeat('=', Helper::width($title)));
  32248. foreach ($description->getNamespaces() as $namespace) {
  32249. if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
  32250. $this->write("\n\n");
  32251. $this->write('**'.$namespace['id'].':**');
  32252. }
  32253. $this->write("\n\n");
  32254. $this->write(implode("\n", array_map(function ($commandName) use ($description) {
  32255. return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName()));
  32256. }, $namespace['commands'])));
  32257. }
  32258. foreach ($description->getCommands() as $command) {
  32259. $this->write("\n\n");
  32260. if (null !== $describeCommand = $this->describeCommand($command, $options)) {
  32261. $this->write($describeCommand);
  32262. }
  32263. }
  32264. }
  32265. private function getApplicationTitle(Application $application): string
  32266. {
  32267. if ('UNKNOWN' !== $application->getName()) {
  32268. if ('UNKNOWN' !== $application->getVersion()) {
  32269. return sprintf('%s %s', $application->getName(), $application->getVersion());
  32270. }
  32271. return $application->getName();
  32272. }
  32273. return 'Console Tool';
  32274. }
  32275. }
  32276. <?php
  32277. namespace Symfony\Component\Console\Tester;
  32278. use Symfony\Component\Console\Command\Command;
  32279. use Symfony\Component\Console\Input\ArrayInput;
  32280. class CommandTester
  32281. {
  32282. use TesterTrait;
  32283. private $command;
  32284. public function __construct(Command $command)
  32285. {
  32286. $this->command = $command;
  32287. }
  32288. public function execute(array $input, array $options = [])
  32289. {
  32290. if (!isset($input['command'])
  32291. && (null !== $application = $this->command->getApplication())
  32292. && $application->getDefinition()->hasArgument('command')
  32293. ) {
  32294. $input = array_merge(['command' => $this->command->getName()], $input);
  32295. }
  32296. $this->input = new ArrayInput($input);
  32297. $this->input->setStream(self::createStream($this->inputs));
  32298. if (isset($options['interactive'])) {
  32299. $this->input->setInteractive($options['interactive']);
  32300. }
  32301. if (!isset($options['decorated'])) {
  32302. $options['decorated'] = false;
  32303. }
  32304. $this->initOutput($options);
  32305. return $this->statusCode = $this->command->run($this->input, $this->output);
  32306. }
  32307. }
  32308. <?php
  32309. namespace Symfony\Component\Console\Tester;
  32310. use PHPUnit\Framework\Assert;
  32311. use Symfony\Component\Console\Input\InputInterface;
  32312. use Symfony\Component\Console\Output\ConsoleOutput;
  32313. use Symfony\Component\Console\Output\OutputInterface;
  32314. use Symfony\Component\Console\Output\StreamOutput;
  32315. use Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful;
  32316. trait TesterTrait
  32317. {
  32318. private $output;
  32319. private $inputs = [];
  32320. private $captureStreamsIndependently = false;
  32321. private $input;
  32322. private $statusCode;
  32323. public function getDisplay(bool $normalize = false)
  32324. {
  32325. if (null === $this->output) {
  32326. throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
  32327. }
  32328. rewind($this->output->getStream());
  32329. $display = stream_get_contents($this->output->getStream());
  32330. if ($normalize) {
  32331. $display = str_replace(\PHP_EOL, "\n", $display);
  32332. }
  32333. return $display;
  32334. }
  32335. public function getErrorOutput(bool $normalize = false)
  32336. {
  32337. if (!$this->captureStreamsIndependently) {
  32338. throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
  32339. }
  32340. rewind($this->output->getErrorOutput()->getStream());
  32341. $display = stream_get_contents($this->output->getErrorOutput()->getStream());
  32342. if ($normalize) {
  32343. $display = str_replace(\PHP_EOL, "\n", $display);
  32344. }
  32345. return $display;
  32346. }
  32347. public function getInput()
  32348. {
  32349. return $this->input;
  32350. }
  32351. public function getOutput()
  32352. {
  32353. return $this->output;
  32354. }
  32355. public function getStatusCode()
  32356. {
  32357. if (null === $this->statusCode) {
  32358. throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?');
  32359. }
  32360. return $this->statusCode;
  32361. }
  32362. public function assertCommandIsSuccessful(string $message = ''): void
  32363. {
  32364. Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message);
  32365. }
  32366. public function setInputs(array $inputs)
  32367. {
  32368. $this->inputs = $inputs;
  32369. return $this;
  32370. }
  32371. private function initOutput(array $options)
  32372. {
  32373. $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
  32374. if (!$this->captureStreamsIndependently) {
  32375. $this->output = new StreamOutput(fopen('php://memory', 'w', false));
  32376. if (isset($options['decorated'])) {
  32377. $this->output->setDecorated($options['decorated']);
  32378. }
  32379. if (isset($options['verbosity'])) {
  32380. $this->output->setVerbosity($options['verbosity']);
  32381. }
  32382. } else {
  32383. $this->output = new ConsoleOutput(
  32384. $options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL,
  32385. $options['decorated'] ?? null
  32386. );
  32387. $errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
  32388. $errorOutput->setFormatter($this->output->getFormatter());
  32389. $errorOutput->setVerbosity($this->output->getVerbosity());
  32390. $errorOutput->setDecorated($this->output->isDecorated());
  32391. $reflectedOutput = new \ReflectionObject($this->output);
  32392. $strErrProperty = $reflectedOutput->getProperty('stderr');
  32393. $strErrProperty->setAccessible(true);
  32394. $strErrProperty->setValue($this->output, $errorOutput);
  32395. $reflectedParent = $reflectedOutput->getParentClass();
  32396. $streamProperty = $reflectedParent->getProperty('stream');
  32397. $streamProperty->setAccessible(true);
  32398. $streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
  32399. }
  32400. }
  32401. private static function createStream(array $inputs)
  32402. {
  32403. $stream = fopen('php://memory', 'r+', false);
  32404. foreach ($inputs as $input) {
  32405. fwrite($stream, $input.\PHP_EOL);
  32406. }
  32407. rewind($stream);
  32408. return $stream;
  32409. }
  32410. }
  32411. <?php
  32412. namespace Symfony\Component\Console\Tester;
  32413. use Symfony\Component\Console\Application;
  32414. use Symfony\Component\Console\Input\ArrayInput;
  32415. class ApplicationTester
  32416. {
  32417. use TesterTrait;
  32418. private $application;
  32419. public function __construct(Application $application)
  32420. {
  32421. $this->application = $application;
  32422. }
  32423. public function run(array $input, array $options = [])
  32424. {
  32425. $prevShellVerbosity = getenv('SHELL_VERBOSITY');
  32426. try {
  32427. $this->input = new ArrayInput($input);
  32428. if (isset($options['interactive'])) {
  32429. $this->input->setInteractive($options['interactive']);
  32430. }
  32431. if ($this->inputs) {
  32432. $this->input->setStream(self::createStream($this->inputs));
  32433. }
  32434. $this->initOutput($options);
  32435. return $this->statusCode = $this->application->run($this->input, $this->output);
  32436. } finally {
  32437. if (false === $prevShellVerbosity) {
  32438. if (\function_exists('putenv')) {
  32439. @putenv('SHELL_VERBOSITY');
  32440. }
  32441. unset($_ENV['SHELL_VERBOSITY']);
  32442. unset($_SERVER['SHELL_VERBOSITY']);
  32443. } else {
  32444. if (\function_exists('putenv')) {
  32445. @putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
  32446. }
  32447. $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
  32448. $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
  32449. }
  32450. }
  32451. }
  32452. }
  32453. <?php
  32454. namespace Symfony\Component\Console\Tester;
  32455. use Symfony\Component\Console\Command\Command;
  32456. use Symfony\Component\Console\Completion\CompletionInput;
  32457. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32458. class CommandCompletionTester
  32459. {
  32460. private $command;
  32461. public function __construct(Command $command)
  32462. {
  32463. $this->command = $command;
  32464. }
  32465. public function complete(array $input): array
  32466. {
  32467. $currentIndex = \count($input);
  32468. if ('' === end($input)) {
  32469. array_pop($input);
  32470. }
  32471. array_unshift($input, $this->command->getName());
  32472. $completionInput = CompletionInput::fromTokens($input, $currentIndex);
  32473. $completionInput->bind($this->command->getDefinition());
  32474. $suggestions = new CompletionSuggestions();
  32475. $this->command->complete($completionInput, $suggestions);
  32476. $options = [];
  32477. foreach ($suggestions->getOptionSuggestions() as $option) {
  32478. $options[] = '--'.$option->getName();
  32479. }
  32480. return array_map('strval', array_merge($options, $suggestions->getValueSuggestions()));
  32481. }
  32482. }
  32483. <?php
  32484. namespace Symfony\Component\Console\Tester\Constraint;
  32485. use PHPUnit\Framework\Constraint\Constraint;
  32486. use Symfony\Component\Console\Command\Command;
  32487. final class CommandIsSuccessful extends Constraint
  32488. {
  32489. public function toString(): string
  32490. {
  32491. return 'is successful';
  32492. }
  32493. protected function matches($other): bool
  32494. {
  32495. return Command::SUCCESS === $other;
  32496. }
  32497. protected function failureDescription($other): string
  32498. {
  32499. return 'the command '.$this->toString();
  32500. }
  32501. protected function additionalFailureDescription($other): string
  32502. {
  32503. $mapping = [
  32504. Command::FAILURE => 'Command failed.',
  32505. Command::INVALID => 'Command was invalid.',
  32506. ];
  32507. return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other);
  32508. }
  32509. }
  32510. <?php
  32511. namespace Symfony\Component\Console\Command;
  32512. use Symfony\Component\Console\Application;
  32513. use Symfony\Component\Console\Completion\CompletionInput;
  32514. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32515. use Symfony\Component\Console\Helper\HelperSet;
  32516. use Symfony\Component\Console\Input\InputDefinition;
  32517. use Symfony\Component\Console\Input\InputInterface;
  32518. use Symfony\Component\Console\Output\OutputInterface;
  32519. final class LazyCommand extends Command
  32520. {
  32521. private $command;
  32522. private $isEnabled;
  32523. public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true)
  32524. {
  32525. $this->setName($name)
  32526. ->setAliases($aliases)
  32527. ->setHidden($isHidden)
  32528. ->setDescription($description);
  32529. $this->command = $commandFactory;
  32530. $this->isEnabled = $isEnabled;
  32531. }
  32532. public function ignoreValidationErrors(): void
  32533. {
  32534. $this->getCommand()->ignoreValidationErrors();
  32535. }
  32536. public function setApplication(?Application $application = null): void
  32537. {
  32538. if ($this->command instanceof parent) {
  32539. $this->command->setApplication($application);
  32540. }
  32541. parent::setApplication($application);
  32542. }
  32543. public function setHelperSet(HelperSet $helperSet): void
  32544. {
  32545. if ($this->command instanceof parent) {
  32546. $this->command->setHelperSet($helperSet);
  32547. }
  32548. parent::setHelperSet($helperSet);
  32549. }
  32550. public function isEnabled(): bool
  32551. {
  32552. return $this->isEnabled ?? $this->getCommand()->isEnabled();
  32553. }
  32554. public function run(InputInterface $input, OutputInterface $output): int
  32555. {
  32556. return $this->getCommand()->run($input, $output);
  32557. }
  32558. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  32559. {
  32560. $this->getCommand()->complete($input, $suggestions);
  32561. }
  32562. public function setCode(callable $code): self
  32563. {
  32564. $this->getCommand()->setCode($code);
  32565. return $this;
  32566. }
  32567. public function mergeApplicationDefinition(bool $mergeArgs = true): void
  32568. {
  32569. $this->getCommand()->mergeApplicationDefinition($mergeArgs);
  32570. }
  32571. public function setDefinition($definition): self
  32572. {
  32573. $this->getCommand()->setDefinition($definition);
  32574. return $this;
  32575. }
  32576. public function getDefinition(): InputDefinition
  32577. {
  32578. return $this->getCommand()->getDefinition();
  32579. }
  32580. public function getNativeDefinition(): InputDefinition
  32581. {
  32582. return $this->getCommand()->getNativeDefinition();
  32583. }
  32584. public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null): self
  32585. {
  32586. $this->getCommand()->addArgument($name, $mode, $description, $default);
  32587. return $this;
  32588. }
  32589. public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): self
  32590. {
  32591. $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default);
  32592. return $this;
  32593. }
  32594. public function setProcessTitle(string $title): self
  32595. {
  32596. $this->getCommand()->setProcessTitle($title);
  32597. return $this;
  32598. }
  32599. public function setHelp(string $help): self
  32600. {
  32601. $this->getCommand()->setHelp($help);
  32602. return $this;
  32603. }
  32604. public function getHelp(): string
  32605. {
  32606. return $this->getCommand()->getHelp();
  32607. }
  32608. public function getProcessedHelp(): string
  32609. {
  32610. return $this->getCommand()->getProcessedHelp();
  32611. }
  32612. public function getSynopsis(bool $short = false): string
  32613. {
  32614. return $this->getCommand()->getSynopsis($short);
  32615. }
  32616. public function addUsage(string $usage): self
  32617. {
  32618. $this->getCommand()->addUsage($usage);
  32619. return $this;
  32620. }
  32621. public function getUsages(): array
  32622. {
  32623. return $this->getCommand()->getUsages();
  32624. }
  32625. public function getHelper(string $name)
  32626. {
  32627. return $this->getCommand()->getHelper($name);
  32628. }
  32629. public function getCommand(): parent
  32630. {
  32631. if (!$this->command instanceof \Closure) {
  32632. return $this->command;
  32633. }
  32634. $command = $this->command = ($this->command)();
  32635. $command->setApplication($this->getApplication());
  32636. if (null !== $this->getHelperSet()) {
  32637. $command->setHelperSet($this->getHelperSet());
  32638. }
  32639. $command->setName($this->getName())
  32640. ->setAliases($this->getAliases())
  32641. ->setHidden($this->isHidden())
  32642. ->setDescription($this->getDescription());
  32643. $command->getDefinition();
  32644. return $command;
  32645. }
  32646. }
  32647. <?php
  32648. namespace Symfony\Component\Console\Command;
  32649. use Symfony\Component\Console\Exception\LogicException;
  32650. use Symfony\Component\Lock\LockFactory;
  32651. use Symfony\Component\Lock\LockInterface;
  32652. use Symfony\Component\Lock\Store\FlockStore;
  32653. use Symfony\Component\Lock\Store\SemaphoreStore;
  32654. trait LockableTrait
  32655. {
  32656. private $lock;
  32657. private function lock(?string $name = null, bool $blocking = false): bool
  32658. {
  32659. if (!class_exists(SemaphoreStore::class)) {
  32660. throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
  32661. }
  32662. if (null !== $this->lock) {
  32663. throw new LogicException('A lock is already in place.');
  32664. }
  32665. if (SemaphoreStore::isSupported()) {
  32666. $store = new SemaphoreStore();
  32667. } else {
  32668. $store = new FlockStore();
  32669. }
  32670. $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
  32671. if (!$this->lock->acquire($blocking)) {
  32672. $this->lock = null;
  32673. return false;
  32674. }
  32675. return true;
  32676. }
  32677. private function release()
  32678. {
  32679. if ($this->lock) {
  32680. $this->lock->release();
  32681. $this->lock = null;
  32682. }
  32683. }
  32684. }
  32685. <?php
  32686. namespace Symfony\Component\Console\Command;
  32687. use Symfony\Component\Console\Completion\CompletionInput;
  32688. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32689. use Symfony\Component\Console\Descriptor\ApplicationDescription;
  32690. use Symfony\Component\Console\Helper\DescriptorHelper;
  32691. use Symfony\Component\Console\Input\InputArgument;
  32692. use Symfony\Component\Console\Input\InputInterface;
  32693. use Symfony\Component\Console\Input\InputOption;
  32694. use Symfony\Component\Console\Output\OutputInterface;
  32695. class HelpCommand extends Command
  32696. {
  32697. private $command;
  32698. protected function configure()
  32699. {
  32700. $this->ignoreValidationErrors();
  32701. $this
  32702. ->setName('help')
  32703. ->setDefinition([
  32704. new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
  32705. new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
  32706. new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
  32707. ])
  32708. ->setDescription('Display help for a command')
  32709. ->setHelp(<<<'EOF'
  32710. The <info>%command.name%</info> command displays help for a given command:
  32711. <info>%command.full_name% list</info>
  32712. You can also output the help in other formats by using the <comment>--format</comment> option:
  32713. <info>%command.full_name% --format=xml list</info>
  32714. To display the list of available commands, please use the <info>list</info> command.
  32715. EOF
  32716. )
  32717. ;
  32718. }
  32719. public function setCommand(Command $command)
  32720. {
  32721. $this->command = $command;
  32722. }
  32723. protected function execute(InputInterface $input, OutputInterface $output)
  32724. {
  32725. if (null === $this->command) {
  32726. $this->command = $this->getApplication()->find($input->getArgument('command_name'));
  32727. }
  32728. $helper = new DescriptorHelper();
  32729. $helper->describe($output, $this->command, [
  32730. 'format' => $input->getOption('format'),
  32731. 'raw_text' => $input->getOption('raw'),
  32732. ]);
  32733. $this->command = null;
  32734. return 0;
  32735. }
  32736. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  32737. {
  32738. if ($input->mustSuggestArgumentValuesFor('command_name')) {
  32739. $descriptor = new ApplicationDescription($this->getApplication());
  32740. $suggestions->suggestValues(array_keys($descriptor->getCommands()));
  32741. return;
  32742. }
  32743. if ($input->mustSuggestOptionValuesFor('format')) {
  32744. $helper = new DescriptorHelper();
  32745. $suggestions->suggestValues($helper->getFormats());
  32746. }
  32747. }
  32748. }
  32749. <?php
  32750. namespace Symfony\Component\Console\Command;
  32751. use Symfony\Component\Console\Completion\CompletionInput;
  32752. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32753. use Symfony\Component\Console\Completion\Output\BashCompletionOutput;
  32754. use Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
  32755. use Symfony\Component\Console\Exception\CommandNotFoundException;
  32756. use Symfony\Component\Console\Exception\ExceptionInterface;
  32757. use Symfony\Component\Console\Input\InputInterface;
  32758. use Symfony\Component\Console\Input\InputOption;
  32759. use Symfony\Component\Console\Output\OutputInterface;
  32760. final class CompleteCommand extends Command
  32761. {
  32762. protected static $defaultName = '|_complete';
  32763. protected static $defaultDescription = 'Internal command to provide shell completion suggestions';
  32764. private $completionOutputs;
  32765. private $isDebug = false;
  32766. public function __construct(array $completionOutputs = [])
  32767. {
  32768. $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class];
  32769. parent::__construct();
  32770. }
  32771. protected function configure(): void
  32772. {
  32773. $this
  32774. ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")')
  32775. ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')
  32776. ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')
  32777. ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'The version of the completion script')
  32778. ;
  32779. }
  32780. protected function initialize(InputInterface $input, OutputInterface $output)
  32781. {
  32782. $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOLEAN);
  32783. }
  32784. protected function execute(InputInterface $input, OutputInterface $output): int
  32785. {
  32786. try {
  32787. $shell = $input->getOption('shell');
  32788. if (!$shell) {
  32789. throw new \RuntimeException('The "--shell" option must be set.');
  32790. }
  32791. if (!$completionOutput = $this->completionOutputs[$shell] ?? false) {
  32792. throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs))));
  32793. }
  32794. $completionInput = $this->createCompletionInput($input);
  32795. $suggestions = new CompletionSuggestions();
  32796. $this->log([
  32797. '',
  32798. '<comment>'.date('Y-m-d H:i:s').'</>',
  32799. '<info>Input:</> <comment>("|" indicates the cursor position)</>',
  32800. ' '.(string) $completionInput,
  32801. '<info>Command:</>',
  32802. ' '.(string) implode(' ', $_SERVER['argv']),
  32803. '<info>Messages:</>',
  32804. ]);
  32805. $command = $this->findCommand($completionInput, $output);
  32806. if (null === $command) {
  32807. $this->log(' No command found, completing using the Application class.');
  32808. $this->getApplication()->complete($completionInput, $suggestions);
  32809. } elseif (
  32810. $completionInput->mustSuggestArgumentValuesFor('command')
  32811. && $command->getName() !== $completionInput->getCompletionValue()
  32812. && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)
  32813. ) {
  32814. $this->log(' No command found, completing using the Application class.');
  32815. $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));
  32816. } else {
  32817. $command->mergeApplicationDefinition();
  32818. $completionInput->bind($command->getDefinition());
  32819. if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
  32820. $this->log(' Completing option names for the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> command.');
  32821. $suggestions->suggestOptions($command->getDefinition()->getOptions());
  32822. } else {
  32823. $this->log([
  32824. ' Completing using the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> class.',
  32825. ' Completing <comment>'.$completionInput->getCompletionType().'</> for <comment>'.$completionInput->getCompletionName().'</>',
  32826. ]);
  32827. if (null !== $compval = $completionInput->getCompletionValue()) {
  32828. $this->log(' Current value: <comment>'.$compval.'</>');
  32829. }
  32830. $command->complete($completionInput, $suggestions);
  32831. }
  32832. }
  32833. $completionOutput = new $completionOutput();
  32834. $this->log('<info>Suggestions:</>');
  32835. if ($options = $suggestions->getOptionSuggestions()) {
  32836. $this->log(' --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options)));
  32837. } elseif ($values = $suggestions->getValueSuggestions()) {
  32838. $this->log(' '.implode(' ', $values));
  32839. } else {
  32840. $this->log(' <comment>No suggestions were provided</>');
  32841. }
  32842. $completionOutput->write($suggestions, $output);
  32843. } catch (\Throwable $e) {
  32844. $this->log([
  32845. '<error>Error!</error>',
  32846. (string) $e,
  32847. ]);
  32848. if ($output->isDebug()) {
  32849. throw $e;
  32850. }
  32851. return 2;
  32852. }
  32853. return 0;
  32854. }
  32855. private function createCompletionInput(InputInterface $input): CompletionInput
  32856. {
  32857. $currentIndex = $input->getOption('current');
  32858. if (!$currentIndex || !ctype_digit($currentIndex)) {
  32859. throw new \RuntimeException('The "--current" option must be set and it must be an integer.');
  32860. }
  32861. $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex);
  32862. try {
  32863. $completionInput->bind($this->getApplication()->getDefinition());
  32864. } catch (ExceptionInterface $e) {
  32865. }
  32866. return $completionInput;
  32867. }
  32868. private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command
  32869. {
  32870. try {
  32871. $inputName = $completionInput->getFirstArgument();
  32872. if (null === $inputName) {
  32873. return null;
  32874. }
  32875. return $this->getApplication()->find($inputName);
  32876. } catch (CommandNotFoundException $e) {
  32877. }
  32878. return null;
  32879. }
  32880. private function log($messages): void
  32881. {
  32882. if (!$this->isDebug) {
  32883. return;
  32884. }
  32885. $commandName = basename($_SERVER['argv'][0]);
  32886. file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\PHP_EOL, (array) $messages).\PHP_EOL, \FILE_APPEND);
  32887. }
  32888. }
  32889. <?php
  32890. namespace Symfony\Component\Console\Command;
  32891. use Symfony\Component\Console\Completion\CompletionInput;
  32892. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32893. use Symfony\Component\Console\Descriptor\ApplicationDescription;
  32894. use Symfony\Component\Console\Helper\DescriptorHelper;
  32895. use Symfony\Component\Console\Input\InputArgument;
  32896. use Symfony\Component\Console\Input\InputInterface;
  32897. use Symfony\Component\Console\Input\InputOption;
  32898. use Symfony\Component\Console\Output\OutputInterface;
  32899. class ListCommand extends Command
  32900. {
  32901. protected function configure()
  32902. {
  32903. $this
  32904. ->setName('list')
  32905. ->setDefinition([
  32906. new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
  32907. new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
  32908. new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
  32909. new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
  32910. ])
  32911. ->setDescription('List commands')
  32912. ->setHelp(<<<'EOF'
  32913. The <info>%command.name%</info> command lists all commands:
  32914. <info>%command.full_name%</info>
  32915. You can also display the commands for a specific namespace:
  32916. <info>%command.full_name% test</info>
  32917. You can also output the information in other formats by using the <comment>--format</comment> option:
  32918. <info>%command.full_name% --format=xml</info>
  32919. It's also possible to get raw list of commands (useful for embedding command runner):
  32920. <info>%command.full_name% --raw</info>
  32921. EOF
  32922. )
  32923. ;
  32924. }
  32925. protected function execute(InputInterface $input, OutputInterface $output)
  32926. {
  32927. $helper = new DescriptorHelper();
  32928. $helper->describe($output, $this->getApplication(), [
  32929. 'format' => $input->getOption('format'),
  32930. 'raw_text' => $input->getOption('raw'),
  32931. 'namespace' => $input->getArgument('namespace'),
  32932. 'short' => $input->getOption('short'),
  32933. ]);
  32934. return 0;
  32935. }
  32936. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  32937. {
  32938. if ($input->mustSuggestArgumentValuesFor('namespace')) {
  32939. $descriptor = new ApplicationDescription($this->getApplication());
  32940. $suggestions->suggestValues(array_keys($descriptor->getNamespaces()));
  32941. return;
  32942. }
  32943. if ($input->mustSuggestOptionValuesFor('format')) {
  32944. $helper = new DescriptorHelper();
  32945. $suggestions->suggestValues($helper->getFormats());
  32946. }
  32947. }
  32948. }
  32949. <?php
  32950. namespace Symfony\Component\Console\Command;
  32951. use Symfony\Component\Console\Completion\CompletionInput;
  32952. use Symfony\Component\Console\Completion\CompletionSuggestions;
  32953. use Symfony\Component\Console\Input\InputArgument;
  32954. use Symfony\Component\Console\Input\InputInterface;
  32955. use Symfony\Component\Console\Input\InputOption;
  32956. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  32957. use Symfony\Component\Console\Output\OutputInterface;
  32958. use Symfony\Component\Process\Process;
  32959. final class DumpCompletionCommand extends Command
  32960. {
  32961. protected static $defaultName = 'completion';
  32962. protected static $defaultDescription = 'Dump the shell completion script';
  32963. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  32964. {
  32965. if ($input->mustSuggestArgumentValuesFor('shell')) {
  32966. $suggestions->suggestValues($this->getSupportedShells());
  32967. }
  32968. }
  32969. protected function configure()
  32970. {
  32971. $fullCommand = $_SERVER['PHP_SELF'];
  32972. $commandName = basename($fullCommand);
  32973. $fullCommand = @realpath($fullCommand) ?: $fullCommand;
  32974. $this
  32975. ->setHelp(<<<EOH
  32976. The <info>%command.name%</> command dumps the shell completion script required
  32977. to use shell autocompletion (currently only bash completion is supported).
  32978. <comment>Static installation
  32979. -------------------</>
  32980. Dump the script to a global completion file and restart your shell:
  32981. <info>%command.full_name% bash | sudo tee /etc/bash_completion.d/{$commandName}</>
  32982. Or dump the script to a local file and source it:
  32983. <info>%command.full_name% bash > completion.sh</>
  32984. <comment># source the file whenever you use the project</>
  32985. <info>source completion.sh</>
  32986. <comment># or add this line at the end of your "~/.bashrc" file:</>
  32987. <info>source /path/to/completion.sh</>
  32988. <comment>Dynamic installation
  32989. --------------------</>
  32990. Add this to the end of your shell configuration file (e.g. <info>"~/.bashrc"</>):
  32991. <info>eval "$({$fullCommand} completion bash)"</>
  32992. EOH
  32993. )
  32994. ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given')
  32995. ->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')
  32996. ;
  32997. }
  32998. protected function execute(InputInterface $input, OutputInterface $output): int
  32999. {
  33000. $commandName = basename($_SERVER['argv'][0]);
  33001. if ($input->getOption('debug')) {
  33002. $this->tailDebugLog($commandName, $output);
  33003. return 0;
  33004. }
  33005. $shell = $input->getArgument('shell') ?? self::guessShell();
  33006. $completionFile = __DIR__.'/../Resources/completion.'.$shell;
  33007. if (!file_exists($completionFile)) {
  33008. $supportedShells = $this->getSupportedShells();
  33009. if ($output instanceof ConsoleOutputInterface) {
  33010. $output = $output->getErrorOutput();
  33011. }
  33012. if ($shell) {
  33013. $output->writeln(sprintf('<error>Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").</>', $shell, implode('", "', $supportedShells)));
  33014. } else {
  33015. $output->writeln(sprintf('<error>Shell not detected, Symfony shell completion only supports "%s").</>', implode('", "', $supportedShells)));
  33016. }
  33017. return 2;
  33018. }
  33019. $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile)));
  33020. return 0;
  33021. }
  33022. private static function guessShell(): string
  33023. {
  33024. return basename($_SERVER['SHELL'] ?? '');
  33025. }
  33026. private function tailDebugLog(string $commandName, OutputInterface $output): void
  33027. {
  33028. $debugFile = sys_get_temp_dir().'/sf_'.$commandName.'.log';
  33029. if (!file_exists($debugFile)) {
  33030. touch($debugFile);
  33031. }
  33032. $process = new Process(['tail', '-f', $debugFile], null, null, null, 0);
  33033. $process->run(function (string $type, string $line) use ($output): void {
  33034. $output->write($line);
  33035. });
  33036. }
  33037. private function getSupportedShells(): array
  33038. {
  33039. $shells = [];
  33040. foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) {
  33041. if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) {
  33042. $shells[] = $file->getExtension();
  33043. }
  33044. }
  33045. return $shells;
  33046. }
  33047. }
  33048. <?php
  33049. namespace Symfony\Component\Console\Command;
  33050. interface SignalableCommandInterface
  33051. {
  33052. public function getSubscribedSignals(): array;
  33053. public function handleSignal(int $signal): void;
  33054. }
  33055. <?php
  33056. namespace Symfony\Component\Console\Command;
  33057. use Symfony\Component\Console\Application;
  33058. use Symfony\Component\Console\Attribute\AsCommand;
  33059. use Symfony\Component\Console\Completion\CompletionInput;
  33060. use Symfony\Component\Console\Completion\CompletionSuggestions;
  33061. use Symfony\Component\Console\Exception\ExceptionInterface;
  33062. use Symfony\Component\Console\Exception\InvalidArgumentException;
  33063. use Symfony\Component\Console\Exception\LogicException;
  33064. use Symfony\Component\Console\Helper\HelperSet;
  33065. use Symfony\Component\Console\Input\InputArgument;
  33066. use Symfony\Component\Console\Input\InputDefinition;
  33067. use Symfony\Component\Console\Input\InputInterface;
  33068. use Symfony\Component\Console\Input\InputOption;
  33069. use Symfony\Component\Console\Output\OutputInterface;
  33070. class Command
  33071. {
  33072. public const SUCCESS = 0;
  33073. public const FAILURE = 1;
  33074. public const INVALID = 2;
  33075. protected static $defaultName;
  33076. protected static $defaultDescription;
  33077. private $application;
  33078. private $name;
  33079. private $processTitle;
  33080. private $aliases = [];
  33081. private $definition;
  33082. private $hidden = false;
  33083. private $help = '';
  33084. private $description = '';
  33085. private $fullDefinition;
  33086. private $ignoreValidationErrors = false;
  33087. private $code;
  33088. private $synopsis = [];
  33089. private $usages = [];
  33090. private $helperSet;
  33091. public static function getDefaultName()
  33092. {
  33093. $class = static::class;
  33094. if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
  33095. return $attribute[0]->newInstance()->name;
  33096. }
  33097. $r = new \ReflectionProperty($class, 'defaultName');
  33098. return $class === $r->class ? static::$defaultName : null;
  33099. }
  33100. public static function getDefaultDescription(): ?string
  33101. {
  33102. $class = static::class;
  33103. if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
  33104. return $attribute[0]->newInstance()->description;
  33105. }
  33106. $r = new \ReflectionProperty($class, 'defaultDescription');
  33107. return $class === $r->class ? static::$defaultDescription : null;
  33108. }
  33109. public function __construct(?string $name = null)
  33110. {
  33111. $this->definition = new InputDefinition();
  33112. if (null === $name && null !== $name = static::getDefaultName()) {
  33113. $aliases = explode('|', $name);
  33114. if ('' === $name = array_shift($aliases)) {
  33115. $this->setHidden(true);
  33116. $name = array_shift($aliases);
  33117. }
  33118. $this->setAliases($aliases);
  33119. }
  33120. if (null !== $name) {
  33121. $this->setName($name);
  33122. }
  33123. if ('' === $this->description) {
  33124. $this->setDescription(static::getDefaultDescription() ?? '');
  33125. }
  33126. $this->configure();
  33127. }
  33128. public function ignoreValidationErrors()
  33129. {
  33130. $this->ignoreValidationErrors = true;
  33131. }
  33132. public function setApplication(?Application $application = null)
  33133. {
  33134. $this->application = $application;
  33135. if ($application) {
  33136. $this->setHelperSet($application->getHelperSet());
  33137. } else {
  33138. $this->helperSet = null;
  33139. }
  33140. $this->fullDefinition = null;
  33141. }
  33142. public function setHelperSet(HelperSet $helperSet)
  33143. {
  33144. $this->helperSet = $helperSet;
  33145. }
  33146. public function getHelperSet()
  33147. {
  33148. return $this->helperSet;
  33149. }
  33150. public function getApplication()
  33151. {
  33152. return $this->application;
  33153. }
  33154. public function isEnabled()
  33155. {
  33156. return true;
  33157. }
  33158. protected function configure()
  33159. {
  33160. }
  33161. protected function execute(InputInterface $input, OutputInterface $output)
  33162. {
  33163. throw new LogicException('You must override the execute() method in the concrete command class.');
  33164. }
  33165. protected function interact(InputInterface $input, OutputInterface $output)
  33166. {
  33167. }
  33168. protected function initialize(InputInterface $input, OutputInterface $output)
  33169. {
  33170. }
  33171. public function run(InputInterface $input, OutputInterface $output)
  33172. {
  33173. $this->mergeApplicationDefinition();
  33174. try {
  33175. $input->bind($this->getDefinition());
  33176. } catch (ExceptionInterface $e) {
  33177. if (!$this->ignoreValidationErrors) {
  33178. throw $e;
  33179. }
  33180. }
  33181. $this->initialize($input, $output);
  33182. if (null !== $this->processTitle) {
  33183. if (\function_exists('cli_set_process_title')) {
  33184. if (!@cli_set_process_title($this->processTitle)) {
  33185. if ('Darwin' === \PHP_OS) {
  33186. $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
  33187. } else {
  33188. cli_set_process_title($this->processTitle);
  33189. }
  33190. }
  33191. } elseif (\function_exists('setproctitle')) {
  33192. setproctitle($this->processTitle);
  33193. } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
  33194. $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
  33195. }
  33196. }
  33197. if ($input->isInteractive()) {
  33198. $this->interact($input, $output);
  33199. }
  33200. if ($input->hasArgument('command') && null === $input->getArgument('command')) {
  33201. $input->setArgument('command', $this->getName());
  33202. }
  33203. $input->validate();
  33204. if ($this->code) {
  33205. $statusCode = ($this->code)($input, $output);
  33206. } else {
  33207. $statusCode = $this->execute($input, $output);
  33208. if (!\is_int($statusCode)) {
  33209. throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode)));
  33210. }
  33211. }
  33212. return is_numeric($statusCode) ? (int) $statusCode : 0;
  33213. }
  33214. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  33215. {
  33216. }
  33217. public function setCode(callable $code)
  33218. {
  33219. if ($code instanceof \Closure) {
  33220. $r = new \ReflectionFunction($code);
  33221. if (null === $r->getClosureThis()) {
  33222. set_error_handler(static function () {});
  33223. try {
  33224. if ($c = \Closure::bind($code, $this)) {
  33225. $code = $c;
  33226. }
  33227. } finally {
  33228. restore_error_handler();
  33229. }
  33230. }
  33231. }
  33232. $this->code = $code;
  33233. return $this;
  33234. }
  33235. public function mergeApplicationDefinition(bool $mergeArgs = true)
  33236. {
  33237. if (null === $this->application) {
  33238. return;
  33239. }
  33240. $this->fullDefinition = new InputDefinition();
  33241. $this->fullDefinition->setOptions($this->definition->getOptions());
  33242. $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions());
  33243. if ($mergeArgs) {
  33244. $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments());
  33245. $this->fullDefinition->addArguments($this->definition->getArguments());
  33246. } else {
  33247. $this->fullDefinition->setArguments($this->definition->getArguments());
  33248. }
  33249. }
  33250. public function setDefinition($definition)
  33251. {
  33252. if ($definition instanceof InputDefinition) {
  33253. $this->definition = $definition;
  33254. } else {
  33255. $this->definition->setDefinition($definition);
  33256. }
  33257. $this->fullDefinition = null;
  33258. return $this;
  33259. }
  33260. public function getDefinition()
  33261. {
  33262. return $this->fullDefinition ?? $this->getNativeDefinition();
  33263. }
  33264. public function getNativeDefinition()
  33265. {
  33266. if (null === $this->definition) {
  33267. throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
  33268. }
  33269. return $this->definition;
  33270. }
  33271. public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null)
  33272. {
  33273. $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
  33274. if (null !== $this->fullDefinition) {
  33275. $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default));
  33276. }
  33277. return $this;
  33278. }
  33279. public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)
  33280. {
  33281. $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
  33282. if (null !== $this->fullDefinition) {
  33283. $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
  33284. }
  33285. return $this;
  33286. }
  33287. public function setName(string $name)
  33288. {
  33289. $this->validateName($name);
  33290. $this->name = $name;
  33291. return $this;
  33292. }
  33293. public function setProcessTitle(string $title)
  33294. {
  33295. $this->processTitle = $title;
  33296. return $this;
  33297. }
  33298. public function getName()
  33299. {
  33300. return $this->name;
  33301. }
  33302. public function setHidden(bool $hidden )
  33303. {
  33304. $this->hidden = $hidden;
  33305. return $this;
  33306. }
  33307. public function isHidden()
  33308. {
  33309. return $this->hidden;
  33310. }
  33311. public function setDescription(string $description)
  33312. {
  33313. $this->description = $description;
  33314. return $this;
  33315. }
  33316. public function getDescription()
  33317. {
  33318. return $this->description;
  33319. }
  33320. public function setHelp(string $help)
  33321. {
  33322. $this->help = $help;
  33323. return $this;
  33324. }
  33325. public function getHelp()
  33326. {
  33327. return $this->help;
  33328. }
  33329. public function getProcessedHelp()
  33330. {
  33331. $name = $this->name;
  33332. $isSingleCommand = $this->application && $this->application->isSingleCommand();
  33333. $placeholders = [
  33334. '%command.name%',
  33335. '%command.full_name%',
  33336. ];
  33337. $replacements = [
  33338. $name,
  33339. $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
  33340. ];
  33341. return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
  33342. }
  33343. public function setAliases(iterable $aliases)
  33344. {
  33345. $list = [];
  33346. foreach ($aliases as $alias) {
  33347. $this->validateName($alias);
  33348. $list[] = $alias;
  33349. }
  33350. $this->aliases = \is_array($aliases) ? $aliases : $list;
  33351. return $this;
  33352. }
  33353. public function getAliases()
  33354. {
  33355. return $this->aliases;
  33356. }
  33357. public function getSynopsis(bool $short = false)
  33358. {
  33359. $key = $short ? 'short' : 'long';
  33360. if (!isset($this->synopsis[$key])) {
  33361. $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
  33362. }
  33363. return $this->synopsis[$key];
  33364. }
  33365. public function addUsage(string $usage)
  33366. {
  33367. if (!str_starts_with($usage, $this->name)) {
  33368. $usage = sprintf('%s %s', $this->name, $usage);
  33369. }
  33370. $this->usages[] = $usage;
  33371. return $this;
  33372. }
  33373. public function getUsages()
  33374. {
  33375. return $this->usages;
  33376. }
  33377. public function getHelper(string $name)
  33378. {
  33379. if (null === $this->helperSet) {
  33380. throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
  33381. }
  33382. return $this->helperSet->get($name);
  33383. }
  33384. private function validateName(string $name)
  33385. {
  33386. if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
  33387. throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
  33388. }
  33389. }
  33390. }
  33391. <?php
  33392. namespace Symfony\Component\Console\Helper;
  33393. use Symfony\Component\Console\Exception\InvalidArgumentException;
  33394. use Symfony\Component\Console\Exception\LogicException;
  33395. class TableStyle
  33396. {
  33397. private $paddingChar = ' ';
  33398. private $horizontalOutsideBorderChar = '-';
  33399. private $horizontalInsideBorderChar = '-';
  33400. private $verticalOutsideBorderChar = '|';
  33401. private $verticalInsideBorderChar = '|';
  33402. private $crossingChar = '+';
  33403. private $crossingTopRightChar = '+';
  33404. private $crossingTopMidChar = '+';
  33405. private $crossingTopLeftChar = '+';
  33406. private $crossingMidRightChar = '+';
  33407. private $crossingBottomRightChar = '+';
  33408. private $crossingBottomMidChar = '+';
  33409. private $crossingBottomLeftChar = '+';
  33410. private $crossingMidLeftChar = '+';
  33411. private $crossingTopLeftBottomChar = '+';
  33412. private $crossingTopMidBottomChar = '+';
  33413. private $crossingTopRightBottomChar = '+';
  33414. private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
  33415. private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
  33416. private $cellHeaderFormat = '<info>%s</info>';
  33417. private $cellRowFormat = '%s';
  33418. private $cellRowContentFormat = ' %s ';
  33419. private $borderFormat = '%s';
  33420. private $padType = \STR_PAD_RIGHT;
  33421. public function setPaddingChar(string $paddingChar)
  33422. {
  33423. if (!$paddingChar) {
  33424. throw new LogicException('The padding char must not be empty.');
  33425. }
  33426. $this->paddingChar = $paddingChar;
  33427. return $this;
  33428. }
  33429. public function getPaddingChar()
  33430. {
  33431. return $this->paddingChar;
  33432. }
  33433. public function setHorizontalBorderChars(string $outside, ?string $inside = null): self
  33434. {
  33435. $this->horizontalOutsideBorderChar = $outside;
  33436. $this->horizontalInsideBorderChar = $inside ?? $outside;
  33437. return $this;
  33438. }
  33439. public function setVerticalBorderChars(string $outside, ?string $inside = null): self
  33440. {
  33441. $this->verticalOutsideBorderChar = $outside;
  33442. $this->verticalInsideBorderChar = $inside ?? $outside;
  33443. return $this;
  33444. }
  33445. public function getBorderChars(): array
  33446. {
  33447. return [
  33448. $this->horizontalOutsideBorderChar,
  33449. $this->verticalOutsideBorderChar,
  33450. $this->horizontalInsideBorderChar,
  33451. $this->verticalInsideBorderChar,
  33452. ];
  33453. }
  33454. public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): self
  33455. {
  33456. $this->crossingChar = $cross;
  33457. $this->crossingTopLeftChar = $topLeft;
  33458. $this->crossingTopMidChar = $topMid;
  33459. $this->crossingTopRightChar = $topRight;
  33460. $this->crossingMidRightChar = $midRight;
  33461. $this->crossingBottomRightChar = $bottomRight;
  33462. $this->crossingBottomMidChar = $bottomMid;
  33463. $this->crossingBottomLeftChar = $bottomLeft;
  33464. $this->crossingMidLeftChar = $midLeft;
  33465. $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
  33466. $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
  33467. $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;
  33468. return $this;
  33469. }
  33470. public function setDefaultCrossingChar(string $char): self
  33471. {
  33472. return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
  33473. }
  33474. public function getCrossingChar()
  33475. {
  33476. return $this->crossingChar;
  33477. }
  33478. public function getCrossingChars(): array
  33479. {
  33480. return [
  33481. $this->crossingChar,
  33482. $this->crossingTopLeftChar,
  33483. $this->crossingTopMidChar,
  33484. $this->crossingTopRightChar,
  33485. $this->crossingMidRightChar,
  33486. $this->crossingBottomRightChar,
  33487. $this->crossingBottomMidChar,
  33488. $this->crossingBottomLeftChar,
  33489. $this->crossingMidLeftChar,
  33490. $this->crossingTopLeftBottomChar,
  33491. $this->crossingTopMidBottomChar,
  33492. $this->crossingTopRightBottomChar,
  33493. ];
  33494. }
  33495. public function setCellHeaderFormat(string $cellHeaderFormat)
  33496. {
  33497. $this->cellHeaderFormat = $cellHeaderFormat;
  33498. return $this;
  33499. }
  33500. public function getCellHeaderFormat()
  33501. {
  33502. return $this->cellHeaderFormat;
  33503. }
  33504. public function setCellRowFormat(string $cellRowFormat)
  33505. {
  33506. $this->cellRowFormat = $cellRowFormat;
  33507. return $this;
  33508. }
  33509. public function getCellRowFormat()
  33510. {
  33511. return $this->cellRowFormat;
  33512. }
  33513. public function setCellRowContentFormat(string $cellRowContentFormat)
  33514. {
  33515. $this->cellRowContentFormat = $cellRowContentFormat;
  33516. return $this;
  33517. }
  33518. public function getCellRowContentFormat()
  33519. {
  33520. return $this->cellRowContentFormat;
  33521. }
  33522. public function setBorderFormat(string $borderFormat)
  33523. {
  33524. $this->borderFormat = $borderFormat;
  33525. return $this;
  33526. }
  33527. public function getBorderFormat()
  33528. {
  33529. return $this->borderFormat;
  33530. }
  33531. public function setPadType(int $padType)
  33532. {
  33533. if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) {
  33534. throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
  33535. }
  33536. $this->padType = $padType;
  33537. return $this;
  33538. }
  33539. public function getPadType()
  33540. {
  33541. return $this->padType;
  33542. }
  33543. public function getHeaderTitleFormat(): string
  33544. {
  33545. return $this->headerTitleFormat;
  33546. }
  33547. public function setHeaderTitleFormat(string $format): self
  33548. {
  33549. $this->headerTitleFormat = $format;
  33550. return $this;
  33551. }
  33552. public function getFooterTitleFormat(): string
  33553. {
  33554. return $this->footerTitleFormat;
  33555. }
  33556. public function setFooterTitleFormat(string $format): self
  33557. {
  33558. $this->footerTitleFormat = $format;
  33559. return $this;
  33560. }
  33561. }
  33562. <?php
  33563. namespace Symfony\Component\Console\Helper;
  33564. class TableRows implements \IteratorAggregate
  33565. {
  33566. private $generator;
  33567. public function __construct(\Closure $generator)
  33568. {
  33569. $this->generator = $generator;
  33570. }
  33571. public function getIterator(): \Traversable
  33572. {
  33573. return ($this->generator)();
  33574. }
  33575. }
  33576. <?php
  33577. namespace Symfony\Component\Console\Helper;
  33578. use Symfony\Component\Console\Formatter\OutputFormatter;
  33579. use Symfony\Component\Console\Output\OutputInterface;
  33580. use Symfony\Component\Console\Question\ChoiceQuestion;
  33581. use Symfony\Component\Console\Question\ConfirmationQuestion;
  33582. use Symfony\Component\Console\Question\Question;
  33583. use Symfony\Component\Console\Style\SymfonyStyle;
  33584. class SymfonyQuestionHelper extends QuestionHelper
  33585. {
  33586. protected function writePrompt(OutputInterface $output, Question $question)
  33587. {
  33588. $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
  33589. $default = $question->getDefault();
  33590. if ($question->isMultiline()) {
  33591. $text .= sprintf(' (press %s to continue)', $this->getEofShortcut());
  33592. }
  33593. switch (true) {
  33594. case null === $default:
  33595. $text = sprintf(' <info>%s</info>:', $text);
  33596. break;
  33597. case $question instanceof ConfirmationQuestion:
  33598. $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
  33599. break;
  33600. case $question instanceof ChoiceQuestion && $question->isMultiselect():
  33601. $choices = $question->getChoices();
  33602. $default = explode(',', $default);
  33603. foreach ($default as $key => $value) {
  33604. $default[$key] = $choices[trim($value)];
  33605. }
  33606. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));
  33607. break;
  33608. case $question instanceof ChoiceQuestion:
  33609. $choices = $question->getChoices();
  33610. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));
  33611. break;
  33612. default:
  33613. $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
  33614. }
  33615. $output->writeln($text);
  33616. $prompt = ' > ';
  33617. if ($question instanceof ChoiceQuestion) {
  33618. $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));
  33619. $prompt = $question->getPrompt();
  33620. }
  33621. $output->write($prompt);
  33622. }
  33623. protected function writeError(OutputInterface $output, \Exception $error)
  33624. {
  33625. if ($output instanceof SymfonyStyle) {
  33626. $output->newLine();
  33627. $output->error($error->getMessage());
  33628. return;
  33629. }
  33630. parent::writeError($output, $error);
  33631. }
  33632. private function getEofShortcut(): string
  33633. {
  33634. if ('Windows' === \PHP_OS_FAMILY) {
  33635. return '<comment>Ctrl+Z</comment> then <comment>Enter</comment>';
  33636. }
  33637. return '<comment>Ctrl+D</comment>';
  33638. }
  33639. }
  33640. <?php
  33641. namespace Symfony\Component\Console\Helper;
  33642. interface HelperInterface
  33643. {
  33644. public function setHelperSet(?HelperSet $helperSet = null);
  33645. public function getHelperSet();
  33646. public function getName();
  33647. }
  33648. <?php
  33649. namespace Symfony\Component\Console\Helper;
  33650. use Symfony\Component\Console\Exception\InvalidArgumentException;
  33651. class TableCell
  33652. {
  33653. private $value;
  33654. private $options = [
  33655. 'rowspan' => 1,
  33656. 'colspan' => 1,
  33657. 'style' => null,
  33658. ];
  33659. public function __construct(string $value = '', array $options = [])
  33660. {
  33661. $this->value = $value;
  33662. if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
  33663. throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
  33664. }
  33665. if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) {
  33666. throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".');
  33667. }
  33668. $this->options = array_merge($this->options, $options);
  33669. }
  33670. public function __toString()
  33671. {
  33672. return $this->value;
  33673. }
  33674. public function getColspan()
  33675. {
  33676. return (int) $this->options['colspan'];
  33677. }
  33678. public function getRowspan()
  33679. {
  33680. return (int) $this->options['rowspan'];
  33681. }
  33682. public function getStyle(): ?TableCellStyle
  33683. {
  33684. return $this->options['style'];
  33685. }
  33686. }
  33687. <?php
  33688. namespace Symfony\Component\Console\Helper;
  33689. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  33690. use Symfony\Component\Console\Output\OutputInterface;
  33691. use Symfony\Component\Process\Exception\ProcessFailedException;
  33692. use Symfony\Component\Process\Process;
  33693. class ProcessHelper extends Helper
  33694. {
  33695. public function run(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
  33696. {
  33697. if (!class_exists(Process::class)) {
  33698. throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
  33699. }
  33700. if ($output instanceof ConsoleOutputInterface) {
  33701. $output = $output->getErrorOutput();
  33702. }
  33703. $formatter = $this->getHelperSet()->get('debug_formatter');
  33704. if ($cmd instanceof Process) {
  33705. $cmd = [$cmd];
  33706. }
  33707. if (!\is_array($cmd)) {
  33708. throw new \TypeError(sprintf('The "command" argument of "%s()" must be an array or a "%s" instance, "%s" given.', __METHOD__, Process::class, get_debug_type($cmd)));
  33709. }
  33710. if (\is_string($cmd[0] ?? null)) {
  33711. $process = new Process($cmd);
  33712. $cmd = [];
  33713. } elseif (($cmd[0] ?? null) instanceof Process) {
  33714. $process = $cmd[0];
  33715. unset($cmd[0]);
  33716. } else {
  33717. throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
  33718. }
  33719. if ($verbosity <= $output->getVerbosity()) {
  33720. $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
  33721. }
  33722. if ($output->isDebug()) {
  33723. $callback = $this->wrapCallback($output, $process, $callback);
  33724. }
  33725. $process->run($callback, $cmd);
  33726. if ($verbosity <= $output->getVerbosity()) {
  33727. $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
  33728. $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
  33729. }
  33730. if (!$process->isSuccessful() && null !== $error) {
  33731. $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
  33732. }
  33733. return $process;
  33734. }
  33735. public function mustRun(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null): Process
  33736. {
  33737. $process = $this->run($output, $cmd, $error, $callback);
  33738. if (!$process->isSuccessful()) {
  33739. throw new ProcessFailedException($process);
  33740. }
  33741. return $process;
  33742. }
  33743. public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable
  33744. {
  33745. if ($output instanceof ConsoleOutputInterface) {
  33746. $output = $output->getErrorOutput();
  33747. }
  33748. $formatter = $this->getHelperSet()->get('debug_formatter');
  33749. return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
  33750. $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
  33751. if (null !== $callback) {
  33752. $callback($type, $buffer);
  33753. }
  33754. };
  33755. }
  33756. private function escapeString(string $str): string
  33757. {
  33758. return str_replace('<', '\\<', $str);
  33759. }
  33760. public function getName(): string
  33761. {
  33762. return 'process';
  33763. }
  33764. }
  33765. <?php
  33766. namespace Symfony\Component\Console\Helper;
  33767. class TableSeparator extends TableCell
  33768. {
  33769. public function __construct(array $options = [])
  33770. {
  33771. parent::__construct('', $options);
  33772. }
  33773. }
  33774. <?php
  33775. namespace Symfony\Component\Console\Helper;
  33776. use Symfony\Component\Console\Formatter\OutputFormatter;
  33777. class FormatterHelper extends Helper
  33778. {
  33779. public function formatSection(string $section, string $message, string $style = 'info')
  33780. {
  33781. return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
  33782. }
  33783. public function formatBlock($messages, string $style, bool $large = false)
  33784. {
  33785. if (!\is_array($messages)) {
  33786. $messages = [$messages];
  33787. }
  33788. $len = 0;
  33789. $lines = [];
  33790. foreach ($messages as $message) {
  33791. $message = OutputFormatter::escape($message);
  33792. $lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
  33793. $len = max(self::width($message) + ($large ? 4 : 2), $len);
  33794. }
  33795. $messages = $large ? [str_repeat(' ', $len)] : [];
  33796. for ($i = 0; isset($lines[$i]); ++$i) {
  33797. $messages[] = $lines[$i].str_repeat(' ', $len - self::width($lines[$i]));
  33798. }
  33799. if ($large) {
  33800. $messages[] = str_repeat(' ', $len);
  33801. }
  33802. for ($i = 0; isset($messages[$i]); ++$i) {
  33803. $messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
  33804. }
  33805. return implode("\n", $messages);
  33806. }
  33807. public function truncate(string $message, int $length, string $suffix = '...')
  33808. {
  33809. $computedLength = $length - self::width($suffix);
  33810. if ($computedLength > self::width($message)) {
  33811. return $message;
  33812. }
  33813. return self::substr($message, 0, $length).$suffix;
  33814. }
  33815. public function getName()
  33816. {
  33817. return 'formatter';
  33818. }
  33819. }
  33820. <?php
  33821. namespace Symfony\Component\Console\Helper;
  33822. use Symfony\Component\Console\Exception\InvalidArgumentException;
  33823. class TableCellStyle
  33824. {
  33825. public const DEFAULT_ALIGN = 'left';
  33826. private const TAG_OPTIONS = [
  33827. 'fg',
  33828. 'bg',
  33829. 'options',
  33830. ];
  33831. private const ALIGN_MAP = [
  33832. 'left' => \STR_PAD_RIGHT,
  33833. 'center' => \STR_PAD_BOTH,
  33834. 'right' => \STR_PAD_LEFT,
  33835. ];
  33836. private $options = [
  33837. 'fg' => 'default',
  33838. 'bg' => 'default',
  33839. 'options' => null,
  33840. 'align' => self::DEFAULT_ALIGN,
  33841. 'cellFormat' => null,
  33842. ];
  33843. public function __construct(array $options = [])
  33844. {
  33845. if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
  33846. throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff)));
  33847. }
  33848. if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) {
  33849. throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP))));
  33850. }
  33851. $this->options = array_merge($this->options, $options);
  33852. }
  33853. public function getOptions(): array
  33854. {
  33855. return $this->options;
  33856. }
  33857. public function getTagOptions()
  33858. {
  33859. return array_filter(
  33860. $this->getOptions(),
  33861. function ($key) {
  33862. return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]);
  33863. },
  33864. \ARRAY_FILTER_USE_KEY
  33865. );
  33866. }
  33867. public function getPadByAlign()
  33868. {
  33869. return self::ALIGN_MAP[$this->getOptions()['align']];
  33870. }
  33871. public function getCellFormat(): ?string
  33872. {
  33873. return $this->getOptions()['cellFormat'];
  33874. }
  33875. }
  33876. <?php
  33877. namespace Symfony\Component\Console\Helper;
  33878. use Symfony\Component\Console\Cursor;
  33879. use Symfony\Component\Console\Exception\LogicException;
  33880. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  33881. use Symfony\Component\Console\Output\ConsoleSectionOutput;
  33882. use Symfony\Component\Console\Output\OutputInterface;
  33883. use Symfony\Component\Console\Terminal;
  33884. final class ProgressBar
  33885. {
  33886. public const FORMAT_VERBOSE = 'verbose';
  33887. public const FORMAT_VERY_VERBOSE = 'very_verbose';
  33888. public const FORMAT_DEBUG = 'debug';
  33889. public const FORMAT_NORMAL = 'normal';
  33890. private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax';
  33891. private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax';
  33892. private const FORMAT_DEBUG_NOMAX = 'debug_nomax';
  33893. private const FORMAT_NORMAL_NOMAX = 'normal_nomax';
  33894. private $barWidth = 28;
  33895. private $barChar;
  33896. private $emptyBarChar = '-';
  33897. private $progressChar = '>';
  33898. private $format;
  33899. private $internalFormat;
  33900. private $redrawFreq = 1;
  33901. private $writeCount;
  33902. private $lastWriteTime;
  33903. private $minSecondsBetweenRedraws = 0;
  33904. private $maxSecondsBetweenRedraws = 1;
  33905. private $output;
  33906. private $step = 0;
  33907. private $max;
  33908. private $startTime;
  33909. private $stepWidth;
  33910. private $percent = 0.0;
  33911. private $messages = [];
  33912. private $overwrite = true;
  33913. private $terminal;
  33914. private $previousMessage;
  33915. private $cursor;
  33916. private static $formatters;
  33917. private static $formats;
  33918. public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)
  33919. {
  33920. if ($output instanceof ConsoleOutputInterface) {
  33921. $output = $output->getErrorOutput();
  33922. }
  33923. $this->output = $output;
  33924. $this->setMaxSteps($max);
  33925. $this->terminal = new Terminal();
  33926. if (0 < $minSecondsBetweenRedraws) {
  33927. $this->redrawFreq = null;
  33928. $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
  33929. }
  33930. if (!$this->output->isDecorated()) {
  33931. $this->overwrite = false;
  33932. $this->redrawFreq = null;
  33933. }
  33934. $this->startTime = time();
  33935. $this->cursor = new Cursor($output);
  33936. }
  33937. public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void
  33938. {
  33939. if (!self::$formatters) {
  33940. self::$formatters = self::initPlaceholderFormatters();
  33941. }
  33942. self::$formatters[$name] = $callable;
  33943. }
  33944. public static function getPlaceholderFormatterDefinition(string $name): ?callable
  33945. {
  33946. if (!self::$formatters) {
  33947. self::$formatters = self::initPlaceholderFormatters();
  33948. }
  33949. return self::$formatters[$name] ?? null;
  33950. }
  33951. public static function setFormatDefinition(string $name, string $format): void
  33952. {
  33953. if (!self::$formats) {
  33954. self::$formats = self::initFormats();
  33955. }
  33956. self::$formats[$name] = $format;
  33957. }
  33958. public static function getFormatDefinition(string $name): ?string
  33959. {
  33960. if (!self::$formats) {
  33961. self::$formats = self::initFormats();
  33962. }
  33963. return self::$formats[$name] ?? null;
  33964. }
  33965. public function setMessage(string $message, string $name = 'message')
  33966. {
  33967. $this->messages[$name] = $message;
  33968. }
  33969. public function getMessage(string $name = 'message')
  33970. {
  33971. return $this->messages[$name] ?? null;
  33972. }
  33973. public function getStartTime(): int
  33974. {
  33975. return $this->startTime;
  33976. }
  33977. public function getMaxSteps(): int
  33978. {
  33979. return $this->max;
  33980. }
  33981. public function getProgress(): int
  33982. {
  33983. return $this->step;
  33984. }
  33985. private function getStepWidth(): int
  33986. {
  33987. return $this->stepWidth;
  33988. }
  33989. public function getProgressPercent(): float
  33990. {
  33991. return $this->percent;
  33992. }
  33993. public function getBarOffset(): float
  33994. {
  33995. return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
  33996. }
  33997. public function getEstimated(): float
  33998. {
  33999. if (!$this->step) {
  34000. return 0;
  34001. }
  34002. return round((time() - $this->startTime) / $this->step * $this->max);
  34003. }
  34004. public function getRemaining(): float
  34005. {
  34006. if (!$this->step) {
  34007. return 0;
  34008. }
  34009. return round((time() - $this->startTime) / $this->step * ($this->max - $this->step));
  34010. }
  34011. public function setBarWidth(int $size)
  34012. {
  34013. $this->barWidth = max(1, $size);
  34014. }
  34015. public function getBarWidth(): int
  34016. {
  34017. return $this->barWidth;
  34018. }
  34019. public function setBarCharacter(string $char)
  34020. {
  34021. $this->barChar = $char;
  34022. }
  34023. public function getBarCharacter(): string
  34024. {
  34025. return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
  34026. }
  34027. public function setEmptyBarCharacter(string $char)
  34028. {
  34029. $this->emptyBarChar = $char;
  34030. }
  34031. public function getEmptyBarCharacter(): string
  34032. {
  34033. return $this->emptyBarChar;
  34034. }
  34035. public function setProgressCharacter(string $char)
  34036. {
  34037. $this->progressChar = $char;
  34038. }
  34039. public function getProgressCharacter(): string
  34040. {
  34041. return $this->progressChar;
  34042. }
  34043. public function setFormat(string $format)
  34044. {
  34045. $this->format = null;
  34046. $this->internalFormat = $format;
  34047. }
  34048. public function setRedrawFrequency(?int $freq)
  34049. {
  34050. $this->redrawFreq = null !== $freq ? max(1, $freq) : null;
  34051. }
  34052. public function minSecondsBetweenRedraws(float $seconds): void
  34053. {
  34054. $this->minSecondsBetweenRedraws = $seconds;
  34055. }
  34056. public function maxSecondsBetweenRedraws(float $seconds): void
  34057. {
  34058. $this->maxSecondsBetweenRedraws = $seconds;
  34059. }
  34060. public function iterate(iterable $iterable, ?int $max = null): iterable
  34061. {
  34062. $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
  34063. foreach ($iterable as $key => $value) {
  34064. yield $key => $value;
  34065. $this->advance();
  34066. }
  34067. $this->finish();
  34068. }
  34069. public function start(?int $max = null)
  34070. {
  34071. $this->startTime = time();
  34072. $this->step = 0;
  34073. $this->percent = 0.0;
  34074. if (null !== $max) {
  34075. $this->setMaxSteps($max);
  34076. }
  34077. $this->display();
  34078. }
  34079. public function advance(int $step = 1)
  34080. {
  34081. $this->setProgress($this->step + $step);
  34082. }
  34083. public function setOverwrite(bool $overwrite)
  34084. {
  34085. $this->overwrite = $overwrite;
  34086. }
  34087. public function setProgress(int $step)
  34088. {
  34089. if ($this->max && $step > $this->max) {
  34090. $this->max = $step;
  34091. } elseif ($step < 0) {
  34092. $step = 0;
  34093. }
  34094. $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
  34095. $prevPeriod = (int) ($this->step / $redrawFreq);
  34096. $currPeriod = (int) ($step / $redrawFreq);
  34097. $this->step = $step;
  34098. $this->percent = $this->max ? (float) $this->step / $this->max : 0;
  34099. $timeInterval = microtime(true) - $this->lastWriteTime;
  34100. if ($this->max === $step) {
  34101. $this->display();
  34102. return;
  34103. }
  34104. if ($timeInterval < $this->minSecondsBetweenRedraws) {
  34105. return;
  34106. }
  34107. if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
  34108. $this->display();
  34109. }
  34110. }
  34111. public function setMaxSteps(int $max)
  34112. {
  34113. $this->format = null;
  34114. $this->max = max(0, $max);
  34115. $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
  34116. }
  34117. public function finish(): void
  34118. {
  34119. if (!$this->max) {
  34120. $this->max = $this->step;
  34121. }
  34122. if ($this->step === $this->max && !$this->overwrite) {
  34123. return;
  34124. }
  34125. $this->setProgress($this->max);
  34126. }
  34127. public function display(): void
  34128. {
  34129. if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
  34130. return;
  34131. }
  34132. if (null === $this->format) {
  34133. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  34134. }
  34135. $this->overwrite($this->buildLine());
  34136. }
  34137. public function clear(): void
  34138. {
  34139. if (!$this->overwrite) {
  34140. return;
  34141. }
  34142. if (null === $this->format) {
  34143. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  34144. }
  34145. $this->overwrite('');
  34146. }
  34147. private function setRealFormat(string $format)
  34148. {
  34149. if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
  34150. $this->format = self::getFormatDefinition($format.'_nomax');
  34151. } elseif (null !== self::getFormatDefinition($format)) {
  34152. $this->format = self::getFormatDefinition($format);
  34153. } else {
  34154. $this->format = $format;
  34155. }
  34156. }
  34157. private function overwrite(string $message): void
  34158. {
  34159. if ($this->previousMessage === $message) {
  34160. return;
  34161. }
  34162. $originalMessage = $message;
  34163. if ($this->overwrite) {
  34164. if (null !== $this->previousMessage) {
  34165. if ($this->output instanceof ConsoleSectionOutput) {
  34166. $messageLines = explode("\n", $this->previousMessage);
  34167. $lineCount = \count($messageLines);
  34168. foreach ($messageLines as $messageLine) {
  34169. $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
  34170. if ($messageLineLength > $this->terminal->getWidth()) {
  34171. $lineCount += floor($messageLineLength / $this->terminal->getWidth());
  34172. }
  34173. }
  34174. $this->output->clear($lineCount);
  34175. } else {
  34176. $lineCount = substr_count($this->previousMessage, "\n");
  34177. for ($i = 0; $i < $lineCount; ++$i) {
  34178. $this->cursor->moveToColumn(1);
  34179. $this->cursor->clearLine();
  34180. $this->cursor->moveUp();
  34181. }
  34182. $this->cursor->moveToColumn(1);
  34183. $this->cursor->clearLine();
  34184. }
  34185. }
  34186. } elseif ($this->step > 0) {
  34187. $message = \PHP_EOL.$message;
  34188. }
  34189. $this->previousMessage = $originalMessage;
  34190. $this->lastWriteTime = microtime(true);
  34191. $this->output->write($message);
  34192. ++$this->writeCount;
  34193. }
  34194. private function determineBestFormat(): string
  34195. {
  34196. switch ($this->output->getVerbosity()) {
  34197. case OutputInterface::VERBOSITY_VERBOSE:
  34198. return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX;
  34199. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  34200. return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX;
  34201. case OutputInterface::VERBOSITY_DEBUG:
  34202. return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX;
  34203. default:
  34204. return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX;
  34205. }
  34206. }
  34207. private static function initPlaceholderFormatters(): array
  34208. {
  34209. return [
  34210. 'bar' => function (self $bar, OutputInterface $output) {
  34211. $completeBars = $bar->getBarOffset();
  34212. $display = str_repeat($bar->getBarCharacter(), $completeBars);
  34213. if ($completeBars < $bar->getBarWidth()) {
  34214. $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));
  34215. $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
  34216. }
  34217. return $display;
  34218. },
  34219. 'elapsed' => function (self $bar) {
  34220. return Helper::formatTime(time() - $bar->getStartTime());
  34221. },
  34222. 'remaining' => function (self $bar) {
  34223. if (!$bar->getMaxSteps()) {
  34224. throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
  34225. }
  34226. return Helper::formatTime($bar->getRemaining());
  34227. },
  34228. 'estimated' => function (self $bar) {
  34229. if (!$bar->getMaxSteps()) {
  34230. throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
  34231. }
  34232. return Helper::formatTime($bar->getEstimated());
  34233. },
  34234. 'memory' => function (self $bar) {
  34235. return Helper::formatMemory(memory_get_usage(true));
  34236. },
  34237. 'current' => function (self $bar) {
  34238. return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
  34239. },
  34240. 'max' => function (self $bar) {
  34241. return $bar->getMaxSteps();
  34242. },
  34243. 'percent' => function (self $bar) {
  34244. return floor($bar->getProgressPercent() * 100);
  34245. },
  34246. ];
  34247. }
  34248. private static function initFormats(): array
  34249. {
  34250. return [
  34251. self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%',
  34252. self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]',
  34253. self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
  34254. self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
  34255. self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
  34256. self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
  34257. self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
  34258. self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
  34259. ];
  34260. }
  34261. private function buildLine(): string
  34262. {
  34263. $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
  34264. $callback = function ($matches) {
  34265. if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
  34266. $text = $formatter($this, $this->output);
  34267. } elseif (isset($this->messages[$matches[1]])) {
  34268. $text = $this->messages[$matches[1]];
  34269. } else {
  34270. return $matches[0];
  34271. }
  34272. if (isset($matches[2])) {
  34273. $text = sprintf('%'.$matches[2], $text);
  34274. }
  34275. return $text;
  34276. };
  34277. $line = preg_replace_callback($regex, $callback, $this->format);
  34278. $linesLength = array_map(function ($subLine) {
  34279. return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r")));
  34280. }, explode("\n", $line));
  34281. $linesWidth = max($linesLength);
  34282. $terminalWidth = $this->terminal->getWidth();
  34283. if ($linesWidth <= $terminalWidth) {
  34284. return $line;
  34285. }
  34286. $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
  34287. return preg_replace_callback($regex, $callback, $this->format);
  34288. }
  34289. }
  34290. <?php
  34291. namespace Symfony\Component\Console\Helper;
  34292. class DebugFormatterHelper extends Helper
  34293. {
  34294. private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
  34295. private $started = [];
  34296. private $count = -1;
  34297. public function start(string $id, string $message, string $prefix = 'RUN')
  34298. {
  34299. $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)];
  34300. return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
  34301. }
  34302. public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR')
  34303. {
  34304. $message = '';
  34305. if ($error) {
  34306. if (isset($this->started[$id]['out'])) {
  34307. $message .= "\n";
  34308. unset($this->started[$id]['out']);
  34309. }
  34310. if (!isset($this->started[$id]['err'])) {
  34311. $message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
  34312. $this->started[$id]['err'] = true;
  34313. }
  34314. $message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
  34315. } else {
  34316. if (isset($this->started[$id]['err'])) {
  34317. $message .= "\n";
  34318. unset($this->started[$id]['err']);
  34319. }
  34320. if (!isset($this->started[$id]['out'])) {
  34321. $message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
  34322. $this->started[$id]['out'] = true;
  34323. }
  34324. $message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
  34325. }
  34326. return $message;
  34327. }
  34328. public function stop(string $id, string $message, bool $successful, string $prefix = 'RES')
  34329. {
  34330. $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
  34331. if ($successful) {
  34332. return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
  34333. }
  34334. $message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
  34335. unset($this->started[$id]['out'], $this->started[$id]['err']);
  34336. return $message;
  34337. }
  34338. private function getBorder(string $id): string
  34339. {
  34340. return sprintf('<bg=%s> </>', self::COLORS[$this->started[$id]['border']]);
  34341. }
  34342. public function getName()
  34343. {
  34344. return 'debug_formatter';
  34345. }
  34346. }
  34347. <?php
  34348. namespace Symfony\Component\Console\Helper;
  34349. use Symfony\Component\Console\Command\Command;
  34350. use Symfony\Component\Console\Exception\InvalidArgumentException;
  34351. /**
  34352. @implements
  34353. */
  34354. class HelperSet implements \IteratorAggregate
  34355. {
  34356. private $helpers = [];
  34357. private $command;
  34358. public function __construct(array $helpers = [])
  34359. {
  34360. foreach ($helpers as $alias => $helper) {
  34361. $this->set($helper, \is_int($alias) ? null : $alias);
  34362. }
  34363. }
  34364. public function set(HelperInterface $helper, ?string $alias = null)
  34365. {
  34366. $this->helpers[$helper->getName()] = $helper;
  34367. if (null !== $alias) {
  34368. $this->helpers[$alias] = $helper;
  34369. }
  34370. $helper->setHelperSet($this);
  34371. }
  34372. public function has(string $name)
  34373. {
  34374. return isset($this->helpers[$name]);
  34375. }
  34376. public function get(string $name)
  34377. {
  34378. if (!$this->has($name)) {
  34379. throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
  34380. }
  34381. return $this->helpers[$name];
  34382. }
  34383. public function setCommand(?Command $command = null)
  34384. {
  34385. trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
  34386. $this->command = $command;
  34387. }
  34388. public function getCommand()
  34389. {
  34390. trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
  34391. return $this->command;
  34392. }
  34393. #[\ReturnTypeWillChange]
  34394. public function getIterator()
  34395. {
  34396. return new \ArrayIterator($this->helpers);
  34397. }
  34398. }
  34399. <?php
  34400. namespace Symfony\Component\Console\Helper;
  34401. use Symfony\Component\Console\Output\OutputInterface;
  34402. use Symfony\Component\VarDumper\Cloner\ClonerInterface;
  34403. use Symfony\Component\VarDumper\Cloner\VarCloner;
  34404. use Symfony\Component\VarDumper\Dumper\CliDumper;
  34405. final class Dumper
  34406. {
  34407. private $output;
  34408. private $dumper;
  34409. private $cloner;
  34410. private $handler;
  34411. public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null)
  34412. {
  34413. $this->output = $output;
  34414. $this->dumper = $dumper;
  34415. $this->cloner = $cloner;
  34416. if (class_exists(CliDumper::class)) {
  34417. $this->handler = function ($var): string {
  34418. $dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
  34419. $dumper->setColors($this->output->isDecorated());
  34420. return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
  34421. };
  34422. } else {
  34423. $this->handler = function ($var): string {
  34424. switch (true) {
  34425. case null === $var:
  34426. return 'null';
  34427. case true === $var:
  34428. return 'true';
  34429. case false === $var:
  34430. return 'false';
  34431. case \is_string($var):
  34432. return '"'.$var.'"';
  34433. default:
  34434. return rtrim(print_r($var, true));
  34435. }
  34436. };
  34437. }
  34438. }
  34439. public function __invoke($var): string
  34440. {
  34441. return ($this->handler)($var);
  34442. }
  34443. }
  34444. <?php
  34445. namespace Symfony\Component\Console\Helper;
  34446. use Symfony\Component\Console\Input\InputAwareInterface;
  34447. use Symfony\Component\Console\Input\InputInterface;
  34448. abstract class InputAwareHelper extends Helper implements InputAwareInterface
  34449. {
  34450. protected $input;
  34451. public function setInput(InputInterface $input)
  34452. {
  34453. $this->input = $input;
  34454. }
  34455. }
  34456. <?php
  34457. namespace Symfony\Component\Console\Helper;
  34458. use Symfony\Component\Console\Cursor;
  34459. use Symfony\Component\Console\Exception\MissingInputException;
  34460. use Symfony\Component\Console\Exception\RuntimeException;
  34461. use Symfony\Component\Console\Formatter\OutputFormatter;
  34462. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  34463. use Symfony\Component\Console\Input\InputInterface;
  34464. use Symfony\Component\Console\Input\StreamableInputInterface;
  34465. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  34466. use Symfony\Component\Console\Output\ConsoleSectionOutput;
  34467. use Symfony\Component\Console\Output\OutputInterface;
  34468. use Symfony\Component\Console\Question\ChoiceQuestion;
  34469. use Symfony\Component\Console\Question\Question;
  34470. use Symfony\Component\Console\Terminal;
  34471. use function Symfony\Component\String\s;
  34472. class QuestionHelper extends Helper
  34473. {
  34474. private $inputStream;
  34475. private static $stty = true;
  34476. private static $stdinIsInteractive;
  34477. public function ask(InputInterface $input, OutputInterface $output, Question $question)
  34478. {
  34479. if ($output instanceof ConsoleOutputInterface) {
  34480. $output = $output->getErrorOutput();
  34481. }
  34482. if (!$input->isInteractive()) {
  34483. return $this->getDefaultAnswer($question);
  34484. }
  34485. if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
  34486. $this->inputStream = $stream;
  34487. }
  34488. try {
  34489. if (!$question->getValidator()) {
  34490. return $this->doAsk($output, $question);
  34491. }
  34492. $interviewer = function () use ($output, $question) {
  34493. return $this->doAsk($output, $question);
  34494. };
  34495. return $this->validateAttempts($interviewer, $output, $question);
  34496. } catch (MissingInputException $exception) {
  34497. $input->setInteractive(false);
  34498. if (null === $fallbackOutput = $this->getDefaultAnswer($question)) {
  34499. throw $exception;
  34500. }
  34501. return $fallbackOutput;
  34502. }
  34503. }
  34504. public function getName()
  34505. {
  34506. return 'question';
  34507. }
  34508. public static function disableStty()
  34509. {
  34510. self::$stty = false;
  34511. }
  34512. private function doAsk(OutputInterface $output, Question $question)
  34513. {
  34514. $this->writePrompt($output, $question);
  34515. $inputStream = $this->inputStream ?: \STDIN;
  34516. $autocomplete = $question->getAutocompleterCallback();
  34517. if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
  34518. $ret = false;
  34519. if ($question->isHidden()) {
  34520. try {
  34521. $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
  34522. $ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
  34523. } catch (RuntimeException $e) {
  34524. if (!$question->isHiddenFallback()) {
  34525. throw $e;
  34526. }
  34527. }
  34528. }
  34529. if (false === $ret) {
  34530. $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true;
  34531. if (!$isBlocked) {
  34532. stream_set_blocking($inputStream, true);
  34533. }
  34534. $ret = $this->readInput($inputStream, $question);
  34535. if (!$isBlocked) {
  34536. stream_set_blocking($inputStream, false);
  34537. }
  34538. if (false === $ret) {
  34539. throw new MissingInputException('Aborted.');
  34540. }
  34541. if ($question->isTrimmable()) {
  34542. $ret = trim($ret);
  34543. }
  34544. }
  34545. } else {
  34546. $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
  34547. $ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
  34548. }
  34549. if ($output instanceof ConsoleSectionOutput) {
  34550. $output->addContent($ret);
  34551. }
  34552. $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
  34553. if ($normalizer = $question->getNormalizer()) {
  34554. return $normalizer($ret);
  34555. }
  34556. return $ret;
  34557. }
  34558. private function getDefaultAnswer(Question $question)
  34559. {
  34560. $default = $question->getDefault();
  34561. if (null === $default) {
  34562. return $default;
  34563. }
  34564. if ($validator = $question->getValidator()) {
  34565. return \call_user_func($question->getValidator(), $default);
  34566. } elseif ($question instanceof ChoiceQuestion) {
  34567. $choices = $question->getChoices();
  34568. if (!$question->isMultiselect()) {
  34569. return $choices[$default] ?? $default;
  34570. }
  34571. $default = explode(',', $default);
  34572. foreach ($default as $k => $v) {
  34573. $v = $question->isTrimmable() ? trim($v) : $v;
  34574. $default[$k] = $choices[$v] ?? $v;
  34575. }
  34576. }
  34577. return $default;
  34578. }
  34579. protected function writePrompt(OutputInterface $output, Question $question)
  34580. {
  34581. $message = $question->getQuestion();
  34582. if ($question instanceof ChoiceQuestion) {
  34583. $output->writeln(array_merge([
  34584. $question->getQuestion(),
  34585. ], $this->formatChoiceQuestionChoices($question, 'info')));
  34586. $message = $question->getPrompt();
  34587. }
  34588. $output->write($message);
  34589. }
  34590. protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag)
  34591. {
  34592. $messages = [];
  34593. $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices())));
  34594. foreach ($choices as $key => $value) {
  34595. $padding = str_repeat(' ', $maxWidth - self::width($key));
  34596. $messages[] = sprintf(" [<$tag>%s$padding</$tag>] %s", $key, $value);
  34597. }
  34598. return $messages;
  34599. }
  34600. protected function writeError(OutputInterface $output, \Exception $error)
  34601. {
  34602. if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
  34603. $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
  34604. } else {
  34605. $message = '<error>'.$error->getMessage().'</error>';
  34606. }
  34607. $output->writeln($message);
  34608. }
  34609. private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
  34610. {
  34611. $cursor = new Cursor($output, $inputStream);
  34612. $fullChoice = '';
  34613. $ret = '';
  34614. $i = 0;
  34615. $ofs = -1;
  34616. $matches = $autocomplete($ret);
  34617. $numMatches = \count($matches);
  34618. $sttyMode = shell_exec('stty -g');
  34619. $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null);
  34620. $r = [$inputStream];
  34621. $w = [];
  34622. shell_exec('stty -icanon -echo');
  34623. $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
  34624. while (!feof($inputStream)) {
  34625. while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) {
  34626. $r = [$inputStream];
  34627. }
  34628. $c = fread($inputStream, 1);
  34629. if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
  34630. shell_exec('stty '.$sttyMode);
  34631. throw new MissingInputException('Aborted.');
  34632. } elseif ("\177" === $c) {
  34633. if (0 === $numMatches && 0 !== $i) {
  34634. --$i;
  34635. $cursor->moveLeft(s($fullChoice)->slice(-1)->width(false));
  34636. $fullChoice = self::substr($fullChoice, 0, $i);
  34637. }
  34638. if (0 === $i) {
  34639. $ofs = -1;
  34640. $matches = $autocomplete($ret);
  34641. $numMatches = \count($matches);
  34642. } else {
  34643. $numMatches = 0;
  34644. }
  34645. $ret = self::substr($ret, 0, $i);
  34646. } elseif ("\033" === $c) {
  34647. $c .= fread($inputStream, 2);
  34648. if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
  34649. if ('A' === $c[2] && -1 === $ofs) {
  34650. $ofs = 0;
  34651. }
  34652. if (0 === $numMatches) {
  34653. continue;
  34654. }
  34655. $ofs += ('A' === $c[2]) ? -1 : 1;
  34656. $ofs = ($numMatches + $ofs) % $numMatches;
  34657. }
  34658. } elseif (\ord($c) < 32) {
  34659. if ("\t" === $c || "\n" === $c) {
  34660. if ($numMatches > 0 && -1 !== $ofs) {
  34661. $ret = (string) $matches[$ofs];
  34662. $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
  34663. $output->write($remainingCharacters);
  34664. $fullChoice .= $remainingCharacters;
  34665. $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding);
  34666. $matches = array_filter(
  34667. $autocomplete($ret),
  34668. function ($match) use ($ret) {
  34669. return '' === $ret || str_starts_with($match, $ret);
  34670. }
  34671. );
  34672. $numMatches = \count($matches);
  34673. $ofs = -1;
  34674. }
  34675. if ("\n" === $c) {
  34676. $output->write($c);
  34677. break;
  34678. }
  34679. $numMatches = 0;
  34680. }
  34681. continue;
  34682. } else {
  34683. if ("\x80" <= $c) {
  34684. $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
  34685. }
  34686. $output->write($c);
  34687. $ret .= $c;
  34688. $fullChoice .= $c;
  34689. ++$i;
  34690. $tempRet = $ret;
  34691. if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
  34692. $tempRet = $this->mostRecentlyEnteredValue($fullChoice);
  34693. }
  34694. $numMatches = 0;
  34695. $ofs = 0;
  34696. foreach ($autocomplete($ret) as $value) {
  34697. if (str_starts_with($value, $tempRet)) {
  34698. $matches[$numMatches++] = $value;
  34699. }
  34700. }
  34701. }
  34702. $cursor->clearLineAfter();
  34703. if ($numMatches > 0 && -1 !== $ofs) {
  34704. $cursor->savePosition();
  34705. $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
  34706. $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');
  34707. $cursor->restorePosition();
  34708. }
  34709. }
  34710. shell_exec('stty '.$sttyMode);
  34711. return $fullChoice;
  34712. }
  34713. private function mostRecentlyEnteredValue(string $entered): string
  34714. {
  34715. if (!str_contains($entered, ',')) {
  34716. return $entered;
  34717. }
  34718. $choices = explode(',', $entered);
  34719. if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) {
  34720. return $lastChoice;
  34721. }
  34722. return $entered;
  34723. }
  34724. private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string
  34725. {
  34726. if ('\\' === \DIRECTORY_SEPARATOR) {
  34727. $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
  34728. if ('phar:' === substr(__FILE__, 0, 5)) {
  34729. $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
  34730. copy($exe, $tmpExe);
  34731. $exe = $tmpExe;
  34732. }
  34733. $sExec = shell_exec('"'.$exe.'"');
  34734. $value = $trimmable ? rtrim($sExec) : $sExec;
  34735. $output->writeln('');
  34736. if (isset($tmpExe)) {
  34737. unlink($tmpExe);
  34738. }
  34739. return $value;
  34740. }
  34741. if (self::$stty && Terminal::hasSttyAvailable()) {
  34742. $sttyMode = shell_exec('stty -g');
  34743. shell_exec('stty -echo');
  34744. } elseif ($this->isInteractiveInput($inputStream)) {
  34745. throw new RuntimeException('Unable to hide the response.');
  34746. }
  34747. $value = fgets($inputStream, 4096);
  34748. if (self::$stty && Terminal::hasSttyAvailable()) {
  34749. shell_exec('stty '.$sttyMode);
  34750. }
  34751. if (false === $value) {
  34752. throw new MissingInputException('Aborted.');
  34753. }
  34754. if ($trimmable) {
  34755. $value = trim($value);
  34756. }
  34757. $output->writeln('');
  34758. return $value;
  34759. }
  34760. private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
  34761. {
  34762. $error = null;
  34763. $attempts = $question->getMaxAttempts();
  34764. while (null === $attempts || $attempts--) {
  34765. if (null !== $error) {
  34766. $this->writeError($output, $error);
  34767. }
  34768. try {
  34769. return $question->getValidator()($interviewer());
  34770. } catch (RuntimeException $e) {
  34771. throw $e;
  34772. } catch (\Exception $error) {
  34773. }
  34774. }
  34775. throw $error;
  34776. }
  34777. private function isInteractiveInput($inputStream): bool
  34778. {
  34779. if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) {
  34780. return false;
  34781. }
  34782. if (null !== self::$stdinIsInteractive) {
  34783. return self::$stdinIsInteractive;
  34784. }
  34785. return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));
  34786. }
  34787. private function readInput($inputStream, Question $question)
  34788. {
  34789. if (!$question->isMultiline()) {
  34790. $cp = $this->setIOCodepage();
  34791. $ret = fgets($inputStream, 4096);
  34792. return $this->resetIOCodepage($cp, $ret);
  34793. }
  34794. $multiLineStreamReader = $this->cloneInputStream($inputStream);
  34795. if (null === $multiLineStreamReader) {
  34796. return false;
  34797. }
  34798. $ret = '';
  34799. $cp = $this->setIOCodepage();
  34800. while (false !== ($char = fgetc($multiLineStreamReader))) {
  34801. if (\PHP_EOL === "{$ret}{$char}") {
  34802. break;
  34803. }
  34804. $ret .= $char;
  34805. }
  34806. return $this->resetIOCodepage($cp, $ret);
  34807. }
  34808. private function setIOCodepage(): int
  34809. {
  34810. if (\function_exists('sapi_windows_cp_set')) {
  34811. $cp = sapi_windows_cp_get();
  34812. sapi_windows_cp_set(sapi_windows_cp_get('oem'));
  34813. return $cp;
  34814. }
  34815. return 0;
  34816. }
  34817. private function resetIOCodepage(int $cp, $input)
  34818. {
  34819. if (0 !== $cp) {
  34820. sapi_windows_cp_set($cp);
  34821. if (false !== $input && '' !== $input) {
  34822. $input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input);
  34823. }
  34824. }
  34825. return $input;
  34826. }
  34827. private function cloneInputStream($inputStream)
  34828. {
  34829. $streamMetaData = stream_get_meta_data($inputStream);
  34830. $seekable = $streamMetaData['seekable'] ?? false;
  34831. $mode = $streamMetaData['mode'] ?? 'rb';
  34832. $uri = $streamMetaData['uri'] ?? null;
  34833. if (null === $uri) {
  34834. return null;
  34835. }
  34836. $cloneStream = fopen($uri, $mode);
  34837. if (true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) {
  34838. $offset = ftell($inputStream);
  34839. rewind($inputStream);
  34840. stream_copy_to_stream($inputStream, $cloneStream);
  34841. fseek($inputStream, $offset);
  34842. fseek($cloneStream, $offset);
  34843. }
  34844. return $cloneStream;
  34845. }
  34846. }
  34847. <?php
  34848. namespace Symfony\Component\Console\Helper;
  34849. use Symfony\Component\Console\Formatter\OutputFormatterInterface;
  34850. use Symfony\Component\String\UnicodeString;
  34851. abstract class Helper implements HelperInterface
  34852. {
  34853. protected $helperSet = null;
  34854. public function setHelperSet(?HelperSet $helperSet = null)
  34855. {
  34856. $this->helperSet = $helperSet;
  34857. }
  34858. public function getHelperSet()
  34859. {
  34860. return $this->helperSet;
  34861. }
  34862. public static function strlen(?string $string)
  34863. {
  34864. trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::width() or Helper::length() instead.', __METHOD__);
  34865. return self::width($string);
  34866. }
  34867. public static function width(?string $string): int
  34868. {
  34869. $string ?? $string = '';
  34870. if (preg_match('//u', $string)) {
  34871. return (new UnicodeString($string))->width(false);
  34872. }
  34873. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  34874. return \strlen($string);
  34875. }
  34876. return mb_strwidth($string, $encoding);
  34877. }
  34878. public static function length(?string $string): int
  34879. {
  34880. $string ?? $string = '';
  34881. if (preg_match('//u', $string)) {
  34882. return (new UnicodeString($string))->length();
  34883. }
  34884. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  34885. return \strlen($string);
  34886. }
  34887. return mb_strlen($string, $encoding);
  34888. }
  34889. public static function substr(?string $string, int $from, ?int $length = null)
  34890. {
  34891. $string ?? $string = '';
  34892. if (false === $encoding = mb_detect_encoding($string, null, true)) {
  34893. return substr($string, $from, $length);
  34894. }
  34895. return mb_substr($string, $from, $length, $encoding);
  34896. }
  34897. public static function formatTime($secs)
  34898. {
  34899. static $timeFormats = [
  34900. [0, '< 1 sec'],
  34901. [1, '1 sec'],
  34902. [2, 'secs', 1],
  34903. [60, '1 min'],
  34904. [120, 'mins', 60],
  34905. [3600, '1 hr'],
  34906. [7200, 'hrs', 3600],
  34907. [86400, '1 day'],
  34908. [172800, 'days', 86400],
  34909. ];
  34910. foreach ($timeFormats as $index => $format) {
  34911. if ($secs >= $format[0]) {
  34912. if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])
  34913. || $index == \count($timeFormats) - 1
  34914. ) {
  34915. if (2 == \count($format)) {
  34916. return $format[1];
  34917. }
  34918. return floor($secs / $format[2]).' '.$format[1];
  34919. }
  34920. }
  34921. }
  34922. }
  34923. public static function formatMemory(int $memory)
  34924. {
  34925. if ($memory >= 1024 * 1024 * 1024) {
  34926. return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
  34927. }
  34928. if ($memory >= 1024 * 1024) {
  34929. return sprintf('%.1f MiB', $memory / 1024 / 1024);
  34930. }
  34931. if ($memory >= 1024) {
  34932. return sprintf('%d KiB', $memory / 1024);
  34933. }
  34934. return sprintf('%d B', $memory);
  34935. }
  34936. public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string)
  34937. {
  34938. trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::removeDecoration() instead.', __METHOD__);
  34939. return self::width(self::removeDecoration($formatter, $string));
  34940. }
  34941. public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
  34942. {
  34943. $isDecorated = $formatter->isDecorated();
  34944. $formatter->setDecorated(false);
  34945. $string = $formatter->format($string ?? '');
  34946. $string = preg_replace("/\033\[[^m]*m/", '', $string ?? '');
  34947. $string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? '');
  34948. $formatter->setDecorated($isDecorated);
  34949. return $string;
  34950. }
  34951. }
  34952. <?php
  34953. namespace Symfony\Component\Console\Helper;
  34954. use Symfony\Component\Console\Exception\InvalidArgumentException;
  34955. use Symfony\Component\Console\Exception\RuntimeException;
  34956. use Symfony\Component\Console\Formatter\OutputFormatter;
  34957. use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
  34958. use Symfony\Component\Console\Output\ConsoleSectionOutput;
  34959. use Symfony\Component\Console\Output\OutputInterface;
  34960. class Table
  34961. {
  34962. private const SEPARATOR_TOP = 0;
  34963. private const SEPARATOR_TOP_BOTTOM = 1;
  34964. private const SEPARATOR_MID = 2;
  34965. private const SEPARATOR_BOTTOM = 3;
  34966. private const BORDER_OUTSIDE = 0;
  34967. private const BORDER_INSIDE = 1;
  34968. private $headerTitle;
  34969. private $footerTitle;
  34970. private $headers = [];
  34971. private $rows = [];
  34972. private $horizontal = false;
  34973. private $effectiveColumnWidths = [];
  34974. private $numberOfColumns;
  34975. private $output;
  34976. private $style;
  34977. private $columnStyles = [];
  34978. private $columnWidths = [];
  34979. private $columnMaxWidths = [];
  34980. private static $styles;
  34981. private $rendered = false;
  34982. public function __construct(OutputInterface $output)
  34983. {
  34984. $this->output = $output;
  34985. if (!self::$styles) {
  34986. self::$styles = self::initStyles();
  34987. }
  34988. $this->setStyle('default');
  34989. }
  34990. public static function setStyleDefinition(string $name, TableStyle $style)
  34991. {
  34992. if (!self::$styles) {
  34993. self::$styles = self::initStyles();
  34994. }
  34995. self::$styles[$name] = $style;
  34996. }
  34997. public static function getStyleDefinition(string $name)
  34998. {
  34999. if (!self::$styles) {
  35000. self::$styles = self::initStyles();
  35001. }
  35002. if (isset(self::$styles[$name])) {
  35003. return self::$styles[$name];
  35004. }
  35005. throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  35006. }
  35007. public function setStyle($name)
  35008. {
  35009. $this->style = $this->resolveStyle($name);
  35010. return $this;
  35011. }
  35012. public function getStyle()
  35013. {
  35014. return $this->style;
  35015. }
  35016. public function setColumnStyle(int $columnIndex, $name)
  35017. {
  35018. $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
  35019. return $this;
  35020. }
  35021. public function getColumnStyle(int $columnIndex)
  35022. {
  35023. return $this->columnStyles[$columnIndex] ?? $this->getStyle();
  35024. }
  35025. public function setColumnWidth(int $columnIndex, int $width)
  35026. {
  35027. $this->columnWidths[$columnIndex] = $width;
  35028. return $this;
  35029. }
  35030. public function setColumnWidths(array $widths)
  35031. {
  35032. $this->columnWidths = [];
  35033. foreach ($widths as $index => $width) {
  35034. $this->setColumnWidth($index, $width);
  35035. }
  35036. return $this;
  35037. }
  35038. public function setColumnMaxWidth(int $columnIndex, int $width): self
  35039. {
  35040. if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
  35041. throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter())));
  35042. }
  35043. $this->columnMaxWidths[$columnIndex] = $width;
  35044. return $this;
  35045. }
  35046. public function setHeaders(array $headers)
  35047. {
  35048. $headers = array_values($headers);
  35049. if (!empty($headers) && !\is_array($headers[0])) {
  35050. $headers = [$headers];
  35051. }
  35052. $this->headers = $headers;
  35053. return $this;
  35054. }
  35055. public function setRows(array $rows)
  35056. {
  35057. $this->rows = [];
  35058. return $this->addRows($rows);
  35059. }
  35060. public function addRows(array $rows)
  35061. {
  35062. foreach ($rows as $row) {
  35063. $this->addRow($row);
  35064. }
  35065. return $this;
  35066. }
  35067. public function addRow($row)
  35068. {
  35069. if ($row instanceof TableSeparator) {
  35070. $this->rows[] = $row;
  35071. return $this;
  35072. }
  35073. if (!\is_array($row)) {
  35074. throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
  35075. }
  35076. $this->rows[] = array_values($row);
  35077. return $this;
  35078. }
  35079. public function appendRow($row): self
  35080. {
  35081. if (!$this->output instanceof ConsoleSectionOutput) {
  35082. throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
  35083. }
  35084. if ($this->rendered) {
  35085. $this->output->clear($this->calculateRowCount());
  35086. }
  35087. $this->addRow($row);
  35088. $this->render();
  35089. return $this;
  35090. }
  35091. public function setRow($column, array $row)
  35092. {
  35093. $this->rows[$column] = $row;
  35094. return $this;
  35095. }
  35096. public function setHeaderTitle(?string $title): self
  35097. {
  35098. $this->headerTitle = $title;
  35099. return $this;
  35100. }
  35101. public function setFooterTitle(?string $title): self
  35102. {
  35103. $this->footerTitle = $title;
  35104. return $this;
  35105. }
  35106. public function setHorizontal(bool $horizontal = true): self
  35107. {
  35108. $this->horizontal = $horizontal;
  35109. return $this;
  35110. }
  35111. public function render()
  35112. {
  35113. $divider = new TableSeparator();
  35114. if ($this->horizontal) {
  35115. $rows = [];
  35116. foreach ($this->headers[0] ?? [] as $i => $header) {
  35117. $rows[$i] = [$header];
  35118. foreach ($this->rows as $row) {
  35119. if ($row instanceof TableSeparator) {
  35120. continue;
  35121. }
  35122. if (isset($row[$i])) {
  35123. $rows[$i][] = $row[$i];
  35124. } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {
  35125. } else {
  35126. $rows[$i][] = null;
  35127. }
  35128. }
  35129. }
  35130. } else {
  35131. $rows = array_merge($this->headers, [$divider], $this->rows);
  35132. }
  35133. $this->calculateNumberOfColumns($rows);
  35134. $rowGroups = $this->buildTableRows($rows);
  35135. $this->calculateColumnsWidth($rowGroups);
  35136. $isHeader = !$this->horizontal;
  35137. $isFirstRow = $this->horizontal;
  35138. $hasTitle = (bool) $this->headerTitle;
  35139. foreach ($rowGroups as $rowGroup) {
  35140. $isHeaderSeparatorRendered = false;
  35141. foreach ($rowGroup as $row) {
  35142. if ($divider === $row) {
  35143. $isHeader = false;
  35144. $isFirstRow = true;
  35145. continue;
  35146. }
  35147. if ($row instanceof TableSeparator) {
  35148. $this->renderRowSeparator();
  35149. continue;
  35150. }
  35151. if (!$row) {
  35152. continue;
  35153. }
  35154. if ($isHeader && !$isHeaderSeparatorRendered) {
  35155. $this->renderRowSeparator(
  35156. $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
  35157. $hasTitle ? $this->headerTitle : null,
  35158. $hasTitle ? $this->style->getHeaderTitleFormat() : null
  35159. );
  35160. $hasTitle = false;
  35161. $isHeaderSeparatorRendered = true;
  35162. }
  35163. if ($isFirstRow) {
  35164. $this->renderRowSeparator(
  35165. $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
  35166. $hasTitle ? $this->headerTitle : null,
  35167. $hasTitle ? $this->style->getHeaderTitleFormat() : null
  35168. );
  35169. $isFirstRow = false;
  35170. $hasTitle = false;
  35171. }
  35172. if ($this->horizontal) {
  35173. $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
  35174. } else {
  35175. $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
  35176. }
  35177. }
  35178. }
  35179. $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
  35180. $this->cleanup();
  35181. $this->rendered = true;
  35182. }
  35183. private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null)
  35184. {
  35185. if (0 === $count = $this->numberOfColumns) {
  35186. return;
  35187. }
  35188. $borders = $this->style->getBorderChars();
  35189. if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
  35190. return;
  35191. }
  35192. $crossings = $this->style->getCrossingChars();
  35193. if (self::SEPARATOR_MID === $type) {
  35194. [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
  35195. } elseif (self::SEPARATOR_TOP === $type) {
  35196. [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
  35197. } elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
  35198. [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
  35199. } else {
  35200. [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
  35201. }
  35202. $markup = $leftChar;
  35203. for ($column = 0; $column < $count; ++$column) {
  35204. $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
  35205. $markup .= $column === $count - 1 ? $rightChar : $midChar;
  35206. }
  35207. if (null !== $title) {
  35208. $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title)));
  35209. $markupLength = Helper::width($markup);
  35210. if ($titleLength > $limit = $markupLength - 4) {
  35211. $titleLength = $limit;
  35212. $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, '')));
  35213. $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
  35214. }
  35215. $titleStart = intdiv($markupLength - $titleLength, 2);
  35216. if (false === mb_detect_encoding($markup, null, true)) {
  35217. $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
  35218. } else {
  35219. $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength);
  35220. }
  35221. }
  35222. $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
  35223. }
  35224. private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string
  35225. {
  35226. $borders = $this->style->getBorderChars();
  35227. return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
  35228. }
  35229. private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null)
  35230. {
  35231. $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
  35232. $columns = $this->getRowColumns($row);
  35233. $last = \count($columns) - 1;
  35234. foreach ($columns as $i => $column) {
  35235. if ($firstCellFormat && 0 === $i) {
  35236. $rowContent .= $this->renderCell($row, $column, $firstCellFormat);
  35237. } else {
  35238. $rowContent .= $this->renderCell($row, $column, $cellFormat);
  35239. }
  35240. $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
  35241. }
  35242. $this->output->writeln($rowContent);
  35243. }
  35244. private function renderCell(array $row, int $column, string $cellFormat): string
  35245. {
  35246. $cell = $row[$column] ?? '';
  35247. $width = $this->effectiveColumnWidths[$column];
  35248. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  35249. foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
  35250. $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
  35251. }
  35252. }
  35253. if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
  35254. $width += \strlen($cell) - mb_strwidth($cell, $encoding);
  35255. }
  35256. $style = $this->getColumnStyle($column);
  35257. if ($cell instanceof TableSeparator) {
  35258. return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));
  35259. }
  35260. $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell));
  35261. $content = sprintf($style->getCellRowContentFormat(), $cell);
  35262. $padType = $style->getPadType();
  35263. if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) {
  35264. $isNotStyledByTag = !preg_match('/^<(\w+|(\w+=[\w,]+;?)*)>.+<\/(\w+|(\w+=\w+;?)*)?>$/', $cell);
  35265. if ($isNotStyledByTag) {
  35266. $cellFormat = $cell->getStyle()->getCellFormat();
  35267. if (!\is_string($cellFormat)) {
  35268. $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';');
  35269. $cellFormat = '<'.$tag.'>%s</>';
  35270. }
  35271. if (strstr($content, '</>')) {
  35272. $content = str_replace('</>', '', $content);
  35273. $width -= 3;
  35274. }
  35275. if (strstr($content, '<fg=default;bg=default>')) {
  35276. $content = str_replace('<fg=default;bg=default>', '', $content);
  35277. $width -= \strlen('<fg=default;bg=default>');
  35278. }
  35279. }
  35280. $padType = $cell->getStyle()->getPadByAlign();
  35281. }
  35282. return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType));
  35283. }
  35284. private function calculateNumberOfColumns(array $rows)
  35285. {
  35286. $columns = [0];
  35287. foreach ($rows as $row) {
  35288. if ($row instanceof TableSeparator) {
  35289. continue;
  35290. }
  35291. $columns[] = $this->getNumberOfColumns($row);
  35292. }
  35293. $this->numberOfColumns = max($columns);
  35294. }
  35295. private function buildTableRows(array $rows): TableRows
  35296. {
  35297. $formatter = $this->output->getFormatter();
  35298. $unmergedRows = [];
  35299. for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
  35300. $rows = $this->fillNextRows($rows, $rowKey);
  35301. foreach ($rows[$rowKey] as $column => $cell) {
  35302. $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
  35303. if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {
  35304. $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
  35305. }
  35306. if (!strstr($cell ?? '', "\n")) {
  35307. continue;
  35308. }
  35309. $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n";
  35310. $escaped = implode($eol, array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode($eol, $cell)));
  35311. $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
  35312. $lines = explode($eol, str_replace($eol, '<fg=default;bg=default></>'.$eol, $cell));
  35313. foreach ($lines as $lineKey => $line) {
  35314. if ($colspan > 1) {
  35315. $line = new TableCell($line, ['colspan' => $colspan]);
  35316. }
  35317. if (0 === $lineKey) {
  35318. $rows[$rowKey][$column] = $line;
  35319. } else {
  35320. if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
  35321. $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
  35322. }
  35323. $unmergedRows[$rowKey][$lineKey][$column] = $line;
  35324. }
  35325. }
  35326. }
  35327. }
  35328. return new TableRows(function () use ($rows, $unmergedRows): \Traversable {
  35329. foreach ($rows as $rowKey => $row) {
  35330. $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];
  35331. if (isset($unmergedRows[$rowKey])) {
  35332. foreach ($unmergedRows[$rowKey] as $row) {
  35333. $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);
  35334. }
  35335. }
  35336. yield $rowGroup;
  35337. }
  35338. });
  35339. }
  35340. private function calculateRowCount(): int
  35341. {
  35342. $numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));
  35343. if ($this->headers) {
  35344. ++$numberOfRows;
  35345. }
  35346. if (\count($this->rows) > 0) {
  35347. ++$numberOfRows;
  35348. }
  35349. return $numberOfRows;
  35350. }
  35351. private function fillNextRows(array $rows, int $line): array
  35352. {
  35353. $unmergedRows = [];
  35354. foreach ($rows[$line] as $column => $cell) {
  35355. if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
  35356. throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell)));
  35357. }
  35358. if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
  35359. $nbLines = $cell->getRowspan() - 1;
  35360. $lines = [$cell];
  35361. if (strstr($cell, "\n")) {
  35362. $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n";
  35363. $lines = explode($eol, str_replace($eol, '<fg=default;bg=default>'.$eol.'</>', $cell));
  35364. $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines;
  35365. $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
  35366. unset($lines[0]);
  35367. }
  35368. $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
  35369. foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
  35370. $value = $lines[$unmergedRowKey - $line] ?? '';
  35371. $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
  35372. if ($nbLines === $unmergedRowKey - $line) {
  35373. break;
  35374. }
  35375. }
  35376. }
  35377. }
  35378. foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
  35379. if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
  35380. foreach ($unmergedRow as $cellKey => $cell) {
  35381. array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
  35382. }
  35383. } else {
  35384. $row = $this->copyRow($rows, $unmergedRowKey - 1);
  35385. foreach ($unmergedRow as $column => $cell) {
  35386. if (!empty($cell)) {
  35387. $row[$column] = $unmergedRow[$column];
  35388. }
  35389. }
  35390. array_splice($rows, $unmergedRowKey, 0, [$row]);
  35391. }
  35392. }
  35393. return $rows;
  35394. }
  35395. private function fillCells(iterable $row)
  35396. {
  35397. $newRow = [];
  35398. foreach ($row as $column => $cell) {
  35399. $newRow[] = $cell;
  35400. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  35401. foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
  35402. $newRow[] = '';
  35403. }
  35404. }
  35405. }
  35406. return $newRow ?: $row;
  35407. }
  35408. private function copyRow(array $rows, int $line): array
  35409. {
  35410. $row = $rows[$line];
  35411. foreach ($row as $cellKey => $cellValue) {
  35412. $row[$cellKey] = '';
  35413. if ($cellValue instanceof TableCell) {
  35414. $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
  35415. }
  35416. }
  35417. return $row;
  35418. }
  35419. private function getNumberOfColumns(array $row): int
  35420. {
  35421. $columns = \count($row);
  35422. foreach ($row as $column) {
  35423. $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
  35424. }
  35425. return $columns;
  35426. }
  35427. private function getRowColumns(array $row): array
  35428. {
  35429. $columns = range(0, $this->numberOfColumns - 1);
  35430. foreach ($row as $cellKey => $cell) {
  35431. if ($cell instanceof TableCell && $cell->getColspan() > 1) {
  35432. $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
  35433. }
  35434. }
  35435. return $columns;
  35436. }
  35437. private function calculateColumnsWidth(iterable $groups)
  35438. {
  35439. for ($column = 0; $column < $this->numberOfColumns; ++$column) {
  35440. $lengths = [];
  35441. foreach ($groups as $group) {
  35442. foreach ($group as $row) {
  35443. if ($row instanceof TableSeparator) {
  35444. continue;
  35445. }
  35446. foreach ($row as $i => $cell) {
  35447. if ($cell instanceof TableCell) {
  35448. $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
  35449. $textLength = Helper::width($textContent);
  35450. if ($textLength > 0) {
  35451. $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));
  35452. foreach ($contentColumns as $position => $content) {
  35453. $row[$i + $position] = $content;
  35454. }
  35455. }
  35456. }
  35457. }
  35458. $lengths[] = $this->getCellWidth($row, $column);
  35459. }
  35460. }
  35461. $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2;
  35462. }
  35463. }
  35464. private function getColumnSeparatorWidth(): int
  35465. {
  35466. return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
  35467. }
  35468. private function getCellWidth(array $row, int $column): int
  35469. {
  35470. $cellWidth = 0;
  35471. if (isset($row[$column])) {
  35472. $cell = $row[$column];
  35473. $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell));
  35474. }
  35475. $columnWidth = $this->columnWidths[$column] ?? 0;
  35476. $cellWidth = max($cellWidth, $columnWidth);
  35477. return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
  35478. }
  35479. private function cleanup()
  35480. {
  35481. $this->effectiveColumnWidths = [];
  35482. $this->numberOfColumns = null;
  35483. }
  35484. private static function initStyles(): array
  35485. {
  35486. $borderless = new TableStyle();
  35487. $borderless
  35488. ->setHorizontalBorderChars('=')
  35489. ->setVerticalBorderChars(' ')
  35490. ->setDefaultCrossingChar(' ')
  35491. ;
  35492. $compact = new TableStyle();
  35493. $compact
  35494. ->setHorizontalBorderChars('')
  35495. ->setVerticalBorderChars('')
  35496. ->setDefaultCrossingChar('')
  35497. ->setCellRowContentFormat('%s ')
  35498. ;
  35499. $styleGuide = new TableStyle();
  35500. $styleGuide
  35501. ->setHorizontalBorderChars('-')
  35502. ->setVerticalBorderChars(' ')
  35503. ->setDefaultCrossingChar(' ')
  35504. ->setCellHeaderFormat('%s')
  35505. ;
  35506. $box = (new TableStyle())
  35507. ->setHorizontalBorderChars('─')
  35508. ->setVerticalBorderChars('│')
  35509. ->setCrossingChars('┼', '┌', '┬', '�', '┤', '┘', '┴', '└', '├')
  35510. ;
  35511. $boxDouble = (new TableStyle())
  35512. ->setHorizontalBorderChars('�', '─')
  35513. ->setVerticalBorderChars('║', '│')
  35514. ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '�', '╧', '╚', '╟', '╠', '╪', '╣')
  35515. ;
  35516. return [
  35517. 'default' => new TableStyle(),
  35518. 'borderless' => $borderless,
  35519. 'compact' => $compact,
  35520. 'symfony-style-guide' => $styleGuide,
  35521. 'box' => $box,
  35522. 'box-double' => $boxDouble,
  35523. ];
  35524. }
  35525. private function resolveStyle($name): TableStyle
  35526. {
  35527. if ($name instanceof TableStyle) {
  35528. return $name;
  35529. }
  35530. if (isset(self::$styles[$name])) {
  35531. return self::$styles[$name];
  35532. }
  35533. throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  35534. }
  35535. }
  35536. <?php
  35537. namespace Symfony\Component\Console\Helper;
  35538. use Symfony\Component\Console\Exception\InvalidArgumentException;
  35539. use Symfony\Component\Console\Exception\LogicException;
  35540. use Symfony\Component\Console\Output\OutputInterface;
  35541. class ProgressIndicator
  35542. {
  35543. private const FORMATS = [
  35544. 'normal' => ' %indicator% %message%',
  35545. 'normal_no_ansi' => ' %message%',
  35546. 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
  35547. 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
  35548. 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
  35549. 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
  35550. ];
  35551. private $output;
  35552. private $startTime;
  35553. private $format;
  35554. private $message;
  35555. private $indicatorValues;
  35556. private $indicatorCurrent;
  35557. private $indicatorChangeInterval;
  35558. private $indicatorUpdateTime;
  35559. private $started = false;
  35560. private static $formatters;
  35561. public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null)
  35562. {
  35563. $this->output = $output;
  35564. if (null === $format) {
  35565. $format = $this->determineBestFormat();
  35566. }
  35567. if (null === $indicatorValues) {
  35568. $indicatorValues = ['-', '\\', '|', '/'];
  35569. }
  35570. $indicatorValues = array_values($indicatorValues);
  35571. if (2 > \count($indicatorValues)) {
  35572. throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
  35573. }
  35574. $this->format = self::getFormatDefinition($format);
  35575. $this->indicatorChangeInterval = $indicatorChangeInterval;
  35576. $this->indicatorValues = $indicatorValues;
  35577. $this->startTime = time();
  35578. }
  35579. public function setMessage(?string $message)
  35580. {
  35581. $this->message = $message;
  35582. $this->display();
  35583. }
  35584. public function start(string $message)
  35585. {
  35586. if ($this->started) {
  35587. throw new LogicException('Progress indicator already started.');
  35588. }
  35589. $this->message = $message;
  35590. $this->started = true;
  35591. $this->startTime = time();
  35592. $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
  35593. $this->indicatorCurrent = 0;
  35594. $this->display();
  35595. }
  35596. public function advance()
  35597. {
  35598. if (!$this->started) {
  35599. throw new LogicException('Progress indicator has not yet been started.');
  35600. }
  35601. if (!$this->output->isDecorated()) {
  35602. return;
  35603. }
  35604. $currentTime = $this->getCurrentTimeInMilliseconds();
  35605. if ($currentTime < $this->indicatorUpdateTime) {
  35606. return;
  35607. }
  35608. $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
  35609. ++$this->indicatorCurrent;
  35610. $this->display();
  35611. }
  35612. public function finish(string $message)
  35613. {
  35614. if (!$this->started) {
  35615. throw new LogicException('Progress indicator has not yet been started.');
  35616. }
  35617. $this->message = $message;
  35618. $this->display();
  35619. $this->output->writeln('');
  35620. $this->started = false;
  35621. }
  35622. public static function getFormatDefinition(string $name)
  35623. {
  35624. return self::FORMATS[$name] ?? null;
  35625. }
  35626. public static function setPlaceholderFormatterDefinition(string $name, callable $callable)
  35627. {
  35628. if (!self::$formatters) {
  35629. self::$formatters = self::initPlaceholderFormatters();
  35630. }
  35631. self::$formatters[$name] = $callable;
  35632. }
  35633. public static function getPlaceholderFormatterDefinition(string $name)
  35634. {
  35635. if (!self::$formatters) {
  35636. self::$formatters = self::initPlaceholderFormatters();
  35637. }
  35638. return self::$formatters[$name] ?? null;
  35639. }
  35640. private function display()
  35641. {
  35642. if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
  35643. return;
  35644. }
  35645. $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
  35646. if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
  35647. return $formatter($this);
  35648. }
  35649. return $matches[0];
  35650. }, $this->format ?? ''));
  35651. }
  35652. private function determineBestFormat(): string
  35653. {
  35654. switch ($this->output->getVerbosity()) {
  35655. case OutputInterface::VERBOSITY_VERBOSE:
  35656. return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
  35657. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  35658. case OutputInterface::VERBOSITY_DEBUG:
  35659. return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
  35660. default:
  35661. return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
  35662. }
  35663. }
  35664. private function overwrite(string $message)
  35665. {
  35666. if ($this->output->isDecorated()) {
  35667. $this->output->write("\x0D\x1B[2K");
  35668. $this->output->write($message);
  35669. } else {
  35670. $this->output->writeln($message);
  35671. }
  35672. }
  35673. private function getCurrentTimeInMilliseconds(): float
  35674. {
  35675. return round(microtime(true) * 1000);
  35676. }
  35677. private static function initPlaceholderFormatters(): array
  35678. {
  35679. return [
  35680. 'indicator' => function (self $indicator) {
  35681. return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
  35682. },
  35683. 'message' => function (self $indicator) {
  35684. return $indicator->message;
  35685. },
  35686. 'elapsed' => function (self $indicator) {
  35687. return Helper::formatTime(time() - $indicator->startTime);
  35688. },
  35689. 'memory' => function () {
  35690. return Helper::formatMemory(memory_get_usage(true));
  35691. },
  35692. ];
  35693. }
  35694. }
  35695. <?php
  35696. namespace Symfony\Component\Console\Helper;
  35697. use Symfony\Component\Console\Descriptor\DescriptorInterface;
  35698. use Symfony\Component\Console\Descriptor\JsonDescriptor;
  35699. use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
  35700. use Symfony\Component\Console\Descriptor\TextDescriptor;
  35701. use Symfony\Component\Console\Descriptor\XmlDescriptor;
  35702. use Symfony\Component\Console\Exception\InvalidArgumentException;
  35703. use Symfony\Component\Console\Output\OutputInterface;
  35704. class DescriptorHelper extends Helper
  35705. {
  35706. private $descriptors = [];
  35707. public function __construct()
  35708. {
  35709. $this
  35710. ->register('txt', new TextDescriptor())
  35711. ->register('xml', new XmlDescriptor())
  35712. ->register('json', new JsonDescriptor())
  35713. ->register('md', new MarkdownDescriptor())
  35714. ;
  35715. }
  35716. public function describe(OutputInterface $output, ?object $object, array $options = [])
  35717. {
  35718. $options = array_merge([
  35719. 'raw_text' => false,
  35720. 'format' => 'txt',
  35721. ], $options);
  35722. if (!isset($this->descriptors[$options['format']])) {
  35723. throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
  35724. }
  35725. $descriptor = $this->descriptors[$options['format']];
  35726. $descriptor->describe($output, $object, $options);
  35727. }
  35728. public function register(string $format, DescriptorInterface $descriptor)
  35729. {
  35730. $this->descriptors[$format] = $descriptor;
  35731. return $this;
  35732. }
  35733. public function getName()
  35734. {
  35735. return 'descriptor';
  35736. }
  35737. public function getFormats(): array
  35738. {
  35739. return array_keys($this->descriptors);
  35740. }
  35741. }
  35742. <?php
  35743. namespace Symfony\Component\Console\DependencyInjection;
  35744. use Symfony\Component\Console\Command\Command;
  35745. use Symfony\Component\Console\Command\LazyCommand;
  35746. use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
  35747. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  35748. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  35749. use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
  35750. use Symfony\Component\DependencyInjection\ContainerBuilder;
  35751. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  35752. use Symfony\Component\DependencyInjection\Reference;
  35753. use Symfony\Component\DependencyInjection\TypedReference;
  35754. class AddConsoleCommandPass implements CompilerPassInterface
  35755. {
  35756. private $commandLoaderServiceId;
  35757. private $commandTag;
  35758. private $noPreloadTag;
  35759. private $privateTagName;
  35760. public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command', string $noPreloadTag = 'container.no_preload', string $privateTagName = 'container.private')
  35761. {
  35762. if (0 < \func_num_args()) {
  35763. trigger_deprecation('symfony/console', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
  35764. }
  35765. $this->commandLoaderServiceId = $commandLoaderServiceId;
  35766. $this->commandTag = $commandTag;
  35767. $this->noPreloadTag = $noPreloadTag;
  35768. $this->privateTagName = $privateTagName;
  35769. }
  35770. public function process(ContainerBuilder $container)
  35771. {
  35772. $commandServices = $container->findTaggedServiceIds($this->commandTag, true);
  35773. $lazyCommandMap = [];
  35774. $lazyCommandRefs = [];
  35775. $serviceIds = [];
  35776. foreach ($commandServices as $id => $tags) {
  35777. $definition = $container->getDefinition($id);
  35778. $definition->addTag($this->noPreloadTag);
  35779. $class = $container->getParameterBag()->resolveValue($definition->getClass());
  35780. if (isset($tags[0]['command'])) {
  35781. $aliases = $tags[0]['command'];
  35782. } else {
  35783. if (!$r = $container->getReflectionClass($class)) {
  35784. throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  35785. }
  35786. if (!$r->isSubclassOf(Command::class)) {
  35787. throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
  35788. }
  35789. $aliases = str_replace('%', '%%', $class::getDefaultName() ?? '');
  35790. }
  35791. $aliases = explode('|', $aliases ?? '');
  35792. $commandName = array_shift($aliases);
  35793. if ($isHidden = '' === $commandName) {
  35794. $commandName = array_shift($aliases);
  35795. }
  35796. if (null === $commandName) {
  35797. if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) {
  35798. $commandId = 'console.command.public_alias.'.$id;
  35799. $container->setAlias($commandId, $id)->setPublic(true);
  35800. $id = $commandId;
  35801. }
  35802. $serviceIds[] = $id;
  35803. continue;
  35804. }
  35805. $description = $tags[0]['description'] ?? null;
  35806. unset($tags[0]);
  35807. $lazyCommandMap[$commandName] = $id;
  35808. $lazyCommandRefs[$id] = new TypedReference($id, $class);
  35809. foreach ($aliases as $alias) {
  35810. $lazyCommandMap[$alias] = $id;
  35811. }
  35812. foreach ($tags as $tag) {
  35813. if (isset($tag['command'])) {
  35814. $aliases[] = $tag['command'];
  35815. $lazyCommandMap[$tag['command']] = $id;
  35816. }
  35817. $description = $description ?? $tag['description'] ?? null;
  35818. }
  35819. $definition->addMethodCall('setName', [$commandName]);
  35820. if ($aliases) {
  35821. $definition->addMethodCall('setAliases', [$aliases]);
  35822. }
  35823. if ($isHidden) {
  35824. $definition->addMethodCall('setHidden', [true]);
  35825. }
  35826. if (!$description) {
  35827. if (!$r = $container->getReflectionClass($class)) {
  35828. throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  35829. }
  35830. if (!$r->isSubclassOf(Command::class)) {
  35831. throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
  35832. }
  35833. $description = str_replace('%', '%%', $class::getDefaultDescription() ?? '');
  35834. }
  35835. if ($description) {
  35836. $definition->addMethodCall('setDescription', [$description]);
  35837. $container->register('.'.$id.'.lazy', LazyCommand::class)
  35838. ->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]);
  35839. $lazyCommandRefs[$id] = new Reference('.'.$id.'.lazy');
  35840. }
  35841. }
  35842. $container
  35843. ->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
  35844. ->setPublic(true)
  35845. ->addTag($this->noPreloadTag)
  35846. ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
  35847. $container->setParameter('console.command.ids', $serviceIds);
  35848. }
  35849. }
  35850. <?php
  35851. namespace Symfony\Component\Console\Exception;
  35852. class LogicException extends \LogicException implements ExceptionInterface
  35853. {
  35854. }
  35855. <?php
  35856. namespace Symfony\Component\Console\Exception;
  35857. class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
  35858. {
  35859. }
  35860. <?php
  35861. namespace Symfony\Component\Console\Exception;
  35862. interface ExceptionInterface extends \Throwable
  35863. {
  35864. }
  35865. <?php
  35866. namespace Symfony\Component\Console\Exception;
  35867. class RuntimeException extends \RuntimeException implements ExceptionInterface
  35868. {
  35869. }
  35870. <?php
  35871. namespace Symfony\Component\Console\Exception;
  35872. class NamespaceNotFoundException extends CommandNotFoundException
  35873. {
  35874. }
  35875. <?php
  35876. namespace Symfony\Component\Console\Exception;
  35877. class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
  35878. {
  35879. }
  35880. <?php
  35881. namespace Symfony\Component\Console\Exception;
  35882. class MissingInputException extends RuntimeException implements ExceptionInterface
  35883. {
  35884. }
  35885. <?php
  35886. namespace Symfony\Component\Console\Exception;
  35887. class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
  35888. {
  35889. private $alternatives;
  35890. public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null)
  35891. {
  35892. parent::__construct($message, $code, $previous);
  35893. $this->alternatives = $alternatives;
  35894. }
  35895. public function getAlternatives()
  35896. {
  35897. return $this->alternatives;
  35898. }
  35899. }
  35900. <?php
  35901. namespace Symfony\Component\Console\Event;
  35902. use Symfony\Component\Console\Command\Command;
  35903. use Symfony\Component\Console\Input\InputInterface;
  35904. use Symfony\Component\Console\Output\OutputInterface;
  35905. final class ConsoleTerminateEvent extends ConsoleEvent
  35906. {
  35907. private $exitCode;
  35908. public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode)
  35909. {
  35910. parent::__construct($command, $input, $output);
  35911. $this->setExitCode($exitCode);
  35912. }
  35913. public function setExitCode(int $exitCode): void
  35914. {
  35915. $this->exitCode = $exitCode;
  35916. }
  35917. public function getExitCode(): int
  35918. {
  35919. return $this->exitCode;
  35920. }
  35921. }
  35922. <?php
  35923. namespace Symfony\Component\Console\Event;
  35924. use Symfony\Component\Console\Command\Command;
  35925. use Symfony\Component\Console\Input\InputInterface;
  35926. use Symfony\Component\Console\Output\OutputInterface;
  35927. final class ConsoleErrorEvent extends ConsoleEvent
  35928. {
  35929. private $error;
  35930. private $exitCode;
  35931. public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null)
  35932. {
  35933. parent::__construct($command, $input, $output);
  35934. $this->error = $error;
  35935. }
  35936. public function getError(): \Throwable
  35937. {
  35938. return $this->error;
  35939. }
  35940. public function setError(\Throwable $error): void
  35941. {
  35942. $this->error = $error;
  35943. }
  35944. public function setExitCode(int $exitCode): void
  35945. {
  35946. $this->exitCode = $exitCode;
  35947. $r = new \ReflectionProperty($this->error, 'code');
  35948. $r->setAccessible(true);
  35949. $r->setValue($this->error, $this->exitCode);
  35950. }
  35951. public function getExitCode(): int
  35952. {
  35953. return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
  35954. }
  35955. }
  35956. <?php
  35957. namespace Symfony\Component\Console\Event;
  35958. final class ConsoleCommandEvent extends ConsoleEvent
  35959. {
  35960. public const RETURN_CODE_DISABLED = 113;
  35961. private $commandShouldRun = true;
  35962. public function disableCommand(): bool
  35963. {
  35964. return $this->commandShouldRun = false;
  35965. }
  35966. public function enableCommand(): bool
  35967. {
  35968. return $this->commandShouldRun = true;
  35969. }
  35970. public function commandShouldRun(): bool
  35971. {
  35972. return $this->commandShouldRun;
  35973. }
  35974. }
  35975. <?php
  35976. namespace Symfony\Component\Console\Event;
  35977. use Symfony\Component\Console\Command\Command;
  35978. use Symfony\Component\Console\Input\InputInterface;
  35979. use Symfony\Component\Console\Output\OutputInterface;
  35980. use Symfony\Contracts\EventDispatcher\Event;
  35981. class ConsoleEvent extends Event
  35982. {
  35983. protected $command;
  35984. private $input;
  35985. private $output;
  35986. public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
  35987. {
  35988. $this->command = $command;
  35989. $this->input = $input;
  35990. $this->output = $output;
  35991. }
  35992. public function getCommand()
  35993. {
  35994. return $this->command;
  35995. }
  35996. public function getInput()
  35997. {
  35998. return $this->input;
  35999. }
  36000. public function getOutput()
  36001. {
  36002. return $this->output;
  36003. }
  36004. }
  36005. <?php
  36006. namespace Symfony\Component\Console\Event;
  36007. use Symfony\Component\Console\Command\Command;
  36008. use Symfony\Component\Console\Input\InputInterface;
  36009. use Symfony\Component\Console\Output\OutputInterface;
  36010. final class ConsoleSignalEvent extends ConsoleEvent
  36011. {
  36012. private $handlingSignal;
  36013. public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal)
  36014. {
  36015. parent::__construct($command, $input, $output);
  36016. $this->handlingSignal = $handlingSignal;
  36017. }
  36018. public function getHandlingSignal(): int
  36019. {
  36020. return $this->handlingSignal;
  36021. }
  36022. }
  36023. <?php
  36024. namespace Symfony\Component\Console\EventListener;
  36025. use Psr\Log\LoggerInterface;
  36026. use Symfony\Component\Console\ConsoleEvents;
  36027. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  36028. use Symfony\Component\Console\Event\ConsoleEvent;
  36029. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  36030. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  36031. class ErrorListener implements EventSubscriberInterface
  36032. {
  36033. private $logger;
  36034. public function __construct(?LoggerInterface $logger = null)
  36035. {
  36036. $this->logger = $logger;
  36037. }
  36038. public function onConsoleError(ConsoleErrorEvent $event)
  36039. {
  36040. if (null === $this->logger) {
  36041. return;
  36042. }
  36043. $error = $event->getError();
  36044. if (!$inputString = $this->getInputString($event)) {
  36045. $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);
  36046. return;
  36047. }
  36048. $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
  36049. }
  36050. public function onConsoleTerminate(ConsoleTerminateEvent $event)
  36051. {
  36052. if (null === $this->logger) {
  36053. return;
  36054. }
  36055. $exitCode = $event->getExitCode();
  36056. if (0 === $exitCode) {
  36057. return;
  36058. }
  36059. if (!$inputString = $this->getInputString($event)) {
  36060. $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);
  36061. return;
  36062. }
  36063. $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
  36064. }
  36065. public static function getSubscribedEvents()
  36066. {
  36067. return [
  36068. ConsoleEvents::ERROR => ['onConsoleError', -128],
  36069. ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],
  36070. ];
  36071. }
  36072. private static function getInputString(ConsoleEvent $event): ?string
  36073. {
  36074. $commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
  36075. $input = $event->getInput();
  36076. if (method_exists($input, '__toString')) {
  36077. if ($commandName) {
  36078. return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
  36079. }
  36080. return (string) $input;
  36081. }
  36082. return $commandName;
  36083. }
  36084. }
  36085. <?php
  36086. use Symfony\Polyfill\Mbstring as p;
  36087. if (!function_exists('mb_convert_encoding')) {
  36088. function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
  36089. }
  36090. if (!function_exists('mb_decode_mimeheader')) {
  36091. function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
  36092. }
  36093. if (!function_exists('mb_encode_mimeheader')) {
  36094. function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
  36095. }
  36096. if (!function_exists('mb_decode_numericentity')) {
  36097. function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
  36098. }
  36099. if (!function_exists('mb_encode_numericentity')) {
  36100. function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
  36101. }
  36102. if (!function_exists('mb_convert_case')) {
  36103. function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
  36104. }
  36105. if (!function_exists('mb_internal_encoding')) {
  36106. function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
  36107. }
  36108. if (!function_exists('mb_language')) {
  36109. function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
  36110. }
  36111. if (!function_exists('mb_list_encodings')) {
  36112. function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
  36113. }
  36114. if (!function_exists('mb_encoding_aliases')) {
  36115. function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
  36116. }
  36117. if (!function_exists('mb_check_encoding')) {
  36118. function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
  36119. }
  36120. if (!function_exists('mb_detect_encoding')) {
  36121. function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
  36122. }
  36123. if (!function_exists('mb_detect_order')) {
  36124. function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
  36125. }
  36126. if (!function_exists('mb_parse_str')) {
  36127. function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
  36128. }
  36129. if (!function_exists('mb_strlen')) {
  36130. function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
  36131. }
  36132. if (!function_exists('mb_strpos')) {
  36133. function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
  36134. }
  36135. if (!function_exists('mb_strtolower')) {
  36136. function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
  36137. }
  36138. if (!function_exists('mb_strtoupper')) {
  36139. function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
  36140. }
  36141. if (!function_exists('mb_substitute_character')) {
  36142. function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
  36143. }
  36144. if (!function_exists('mb_substr')) {
  36145. function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
  36146. }
  36147. if (!function_exists('mb_stripos')) {
  36148. function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
  36149. }
  36150. if (!function_exists('mb_stristr')) {
  36151. function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
  36152. }
  36153. if (!function_exists('mb_strrchr')) {
  36154. function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
  36155. }
  36156. if (!function_exists('mb_strrichr')) {
  36157. function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
  36158. }
  36159. if (!function_exists('mb_strripos')) {
  36160. function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
  36161. }
  36162. if (!function_exists('mb_strrpos')) {
  36163. function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
  36164. }
  36165. if (!function_exists('mb_strstr')) {
  36166. function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
  36167. }
  36168. if (!function_exists('mb_get_info')) {
  36169. function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); }
  36170. }
  36171. if (!function_exists('mb_http_output')) {
  36172. function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
  36173. }
  36174. if (!function_exists('mb_strwidth')) {
  36175. function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
  36176. }
  36177. if (!function_exists('mb_substr_count')) {
  36178. function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
  36179. }
  36180. if (!function_exists('mb_output_handler')) {
  36181. function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
  36182. }
  36183. if (!function_exists('mb_http_input')) {
  36184. function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
  36185. }
  36186. if (!function_exists('mb_convert_variables')) {
  36187. function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
  36188. }
  36189. if (!function_exists('mb_ord')) {
  36190. function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
  36191. }
  36192. if (!function_exists('mb_chr')) {
  36193. function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
  36194. }
  36195. if (!function_exists('mb_scrub')) {
  36196. function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
  36197. }
  36198. if (!function_exists('mb_str_split')) {
  36199. function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
  36200. }
  36201. if (!function_exists('mb_str_pad')) {
  36202. function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
  36203. }
  36204. if (!function_exists('mb_ucfirst')) {
  36205. function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
  36206. }
  36207. if (!function_exists('mb_lcfirst')) {
  36208. function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
  36209. }
  36210. if (!function_exists('mb_trim')) {
  36211. function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
  36212. }
  36213. if (!function_exists('mb_ltrim')) {
  36214. function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
  36215. }
  36216. if (!function_exists('mb_rtrim')) {
  36217. function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
  36218. }
  36219. if (extension_loaded('mbstring')) {
  36220. return;
  36221. }
  36222. if (!defined('MB_CASE_UPPER')) {
  36223. define('MB_CASE_UPPER', 0);
  36224. }
  36225. if (!defined('MB_CASE_LOWER')) {
  36226. define('MB_CASE_LOWER', 1);
  36227. }
  36228. if (!defined('MB_CASE_TITLE')) {
  36229. define('MB_CASE_TITLE', 2);
  36230. }
  36231. <?php
  36232. return [
  36233. 'İ' => 'i̇',
  36234. 'µ' => 'μ',
  36235. 'Å¿' => 's',
  36236. 'ͅ' => 'ι',
  36237. 'ς' => 'σ',
  36238. '�' => 'β',
  36239. 'ϑ' => 'θ',
  36240. 'ϕ' => 'φ',
  36241. 'Ï–' => 'Ï€',
  36242. 'ϰ' => 'κ',
  36243. 'ϱ' => '�',
  36244. 'ϵ' => 'ε',
  36245. 'ẛ' => 'ṡ',
  36246. 'ι' => 'ι',
  36247. 'ß' => 'ss',
  36248. 'ʼn' => 'ʼn',
  36249. 'ǰ' => 'ǰ',
  36250. '�' => '�',
  36251. 'ΰ' => 'ΰ',
  36252. 'Ö‡' => 'Õ¥Ö‚',
  36253. 'ẖ' => 'ẖ',
  36254. 'ẗ' => 'ẗ',
  36255. 'ẘ' => 'ẘ',
  36256. 'ẙ' => 'ẙ',
  36257. 'ẚ' => 'aʾ',
  36258. 'ẞ' => 'ss',
  36259. '�' => '�',
  36260. 'á½’' => 'á½’',
  36261. 'á½”' => 'á½”',
  36262. 'á½–' => 'á½–',
  36263. 'ᾀ' => 'ἀι',
  36264. '�' => '�ι',
  36265. 'ᾂ' => 'ἂι',
  36266. 'ᾃ' => 'ἃι',
  36267. 'ᾄ' => 'ἄι',
  36268. 'ᾅ' => 'ἅι',
  36269. 'ᾆ' => 'ἆι',
  36270. 'ᾇ' => 'ἇι',
  36271. 'ᾈ' => 'ἀι',
  36272. 'ᾉ' => '�ι',
  36273. 'ᾊ' => 'ἂι',
  36274. 'ᾋ' => 'ἃι',
  36275. 'ᾌ' => 'ἄι',
  36276. '�' => 'ἅι',
  36277. 'ᾎ' => 'ἆι',
  36278. '�' => 'ἇι',
  36279. '�' => 'ἠι',
  36280. 'ᾑ' => 'ἡι',
  36281. 'ᾒ' => 'ἢι',
  36282. 'ᾓ' => 'ἣι',
  36283. 'ᾔ' => 'ἤι',
  36284. 'ᾕ' => 'ἥι',
  36285. 'ᾖ' => 'ἦι',
  36286. 'ᾗ' => 'ἧι',
  36287. 'ᾘ' => 'ἠι',
  36288. 'ᾙ' => 'ἡι',
  36289. 'ᾚ' => 'ἢι',
  36290. 'ᾛ' => 'ἣι',
  36291. 'ᾜ' => 'ἤι',
  36292. '�' => 'ἥι',
  36293. 'ᾞ' => 'ἦι',
  36294. 'ᾟ' => 'ἧι',
  36295. 'ᾠ' => 'ὠι',
  36296. 'ᾡ' => 'ὡι',
  36297. 'ᾢ' => 'ὢι',
  36298. 'ᾣ' => 'ὣι',
  36299. 'ᾤ' => 'ὤι',
  36300. 'ᾥ' => 'ὥι',
  36301. 'ᾦ' => 'ὦι',
  36302. 'ᾧ' => 'ὧι',
  36303. 'ᾨ' => 'ὠι',
  36304. 'ᾩ' => 'ὡι',
  36305. 'ᾪ' => 'ὢι',
  36306. 'ᾫ' => 'ὣι',
  36307. 'ᾬ' => 'ὤι',
  36308. 'ᾭ' => 'ὥι',
  36309. 'ᾮ' => 'ὦι',
  36310. 'ᾯ' => 'ὧι',
  36311. 'ᾲ' => 'ὰι',
  36312. 'ᾳ' => 'αι',
  36313. 'ᾴ' => 'άι',
  36314. 'á¾¶' => 'á¾¶',
  36315. 'ᾷ' => 'ᾶι',
  36316. 'ᾼ' => 'αι',
  36317. 'ῂ' => 'ὴι',
  36318. 'ῃ' => 'ηι',
  36319. 'ῄ' => 'ήι',
  36320. 'ῆ' => 'ῆ',
  36321. 'ῇ' => 'ῆι',
  36322. 'ῌ' => 'ηι',
  36323. 'á¿’' => 'á¿’',
  36324. 'á¿–' => 'á¿–',
  36325. 'á¿—' => 'á¿—',
  36326. 'á¿¢' => 'á¿¢',
  36327. 'ῤ' => 'ῤ',
  36328. 'ῦ' => 'ῦ',
  36329. 'á¿§' => 'á¿§',
  36330. 'ῲ' => 'ὼι',
  36331. 'ῳ' => 'ωι',
  36332. 'ῴ' => 'ώι',
  36333. 'á¿¶' => 'á¿¶',
  36334. 'ῷ' => 'ῶι',
  36335. 'ῼ' => 'ωι',
  36336. 'ff' => 'ff',
  36337. '�' => 'fi',
  36338. 'fl' => 'fl',
  36339. 'ffi' => 'ffi',
  36340. 'ffl' => 'ffl',
  36341. 'ſt' => 'st',
  36342. 'st' => 'st',
  36343. 'ﬓ' => 'մն',
  36344. 'ﬔ' => 'մե',
  36345. 'ﬕ' => 'մի',
  36346. 'ﬖ' => 'վն',
  36347. 'ﬗ' => 'մխ',
  36348. ];
  36349. <?php
  36350. return array (
  36351. 'A' => 'a',
  36352. 'B' => 'b',
  36353. 'C' => 'c',
  36354. 'D' => 'd',
  36355. 'E' => 'e',
  36356. 'F' => 'f',
  36357. 'G' => 'g',
  36358. 'H' => 'h',
  36359. 'I' => 'i',
  36360. 'J' => 'j',
  36361. 'K' => 'k',
  36362. 'L' => 'l',
  36363. 'M' => 'm',
  36364. 'N' => 'n',
  36365. 'O' => 'o',
  36366. 'P' => 'p',
  36367. 'Q' => 'q',
  36368. 'R' => 'r',
  36369. 'S' => 's',
  36370. 'T' => 't',
  36371. 'U' => 'u',
  36372. 'V' => 'v',
  36373. 'W' => 'w',
  36374. 'X' => 'x',
  36375. 'Y' => 'y',
  36376. 'Z' => 'z',
  36377. 'À' => 'à',
  36378. '�' => 'á',
  36379. 'Â' => 'â',
  36380. 'Ã' => 'ã',
  36381. 'Ä' => 'ä',
  36382. 'Ã…' => 'Ã¥',
  36383. 'Æ' => 'æ',
  36384. 'Ç' => 'ç',
  36385. 'È' => 'è',
  36386. 'É' => 'é',
  36387. 'Ê' => 'ê',
  36388. 'Ë' => 'ë',
  36389. 'Ì' => 'ì',
  36390. '�' => 'í',
  36391. 'Î' => 'î',
  36392. '�' => 'ï',
  36393. '�' => 'ð',
  36394. 'Ñ' => 'ñ',
  36395. 'Ò' => 'ò',
  36396. 'Ó' => 'ó',
  36397. 'Ô' => 'ô',
  36398. 'Õ' => 'õ',
  36399. 'Ö' => 'ö',
  36400. 'Ø' => 'ø',
  36401. 'Ù' => 'ù',
  36402. 'Ú' => 'ú',
  36403. 'Û' => 'û',
  36404. 'Ü' => 'ü',
  36405. '�' => 'ý',
  36406. 'Þ' => 'þ',
  36407. 'Ā' => '�',
  36408. 'Ă' => 'ă',
  36409. 'Ä„' => 'Ä…',
  36410. 'Ć' => 'ć',
  36411. 'Ĉ' => 'ĉ',
  36412. 'ÄŠ' => 'Ä‹',
  36413. 'Č' => '�',
  36414. 'Ď' => '�',
  36415. '�' => 'đ',
  36416. 'Ä’' => 'Ä“',
  36417. 'Ä”' => 'Ä•',
  36418. 'Ä–' => 'Ä—',
  36419. 'Ę' => 'ę',
  36420. 'Äš' => 'Ä›',
  36421. 'Ĝ' => '�',
  36422. 'Äž' => 'ÄŸ',
  36423. 'Ä ' => 'Ä¡',
  36424. 'Ä¢' => 'Ä£',
  36425. 'Ĥ' => 'ĥ',
  36426. 'Ħ' => 'ħ',
  36427. 'Ĩ' => 'ĩ',
  36428. 'Ī' => 'ī',
  36429. 'Ĭ' => 'ĭ',
  36430. 'Į' => 'į',
  36431. 'İ' => 'i̇',
  36432. 'IJ' => 'ij',
  36433. 'Ĵ' => 'ĵ',
  36434. 'Ķ' => 'ķ',
  36435. 'Ĺ' => 'ĺ',
  36436. 'Ļ' => 'ļ',
  36437. 'Ľ' => 'ľ',
  36438. 'Ä¿' => 'Å€',
  36439. '�' => 'ł',
  36440. 'Ń' => 'ń',
  36441. 'Ņ' => 'ņ',
  36442. 'Ň' => 'ň',
  36443. 'ÅŠ' => 'Å‹',
  36444. 'Ō' => '�',
  36445. 'Ŏ' => '�',
  36446. '�' => 'ő',
  36447. 'Å’' => 'Å“',
  36448. 'Å”' => 'Å•',
  36449. 'Å–' => 'Å—',
  36450. 'Ř' => 'ř',
  36451. 'Åš' => 'Å›',
  36452. 'Ŝ' => '�',
  36453. 'Åž' => 'ÅŸ',
  36454. 'Å ' => 'Å¡',
  36455. 'Å¢' => 'Å£',
  36456. 'Ť' => 'ť',
  36457. 'Ŧ' => 'ŧ',
  36458. 'Ũ' => 'ũ',
  36459. 'Ū' => 'ū',
  36460. 'Ŭ' => 'ŭ',
  36461. 'Ů' => 'ů',
  36462. 'Ű' => 'ű',
  36463. 'Ų' => 'ų',
  36464. 'Ŵ' => 'ŵ',
  36465. 'Ŷ' => 'ŷ',
  36466. 'Ÿ' => 'ÿ',
  36467. 'Ź' => 'ź',
  36468. 'Ż' => 'ż',
  36469. 'Ž' => 'ž',
  36470. '�' => 'ɓ',
  36471. 'Ƃ' => 'ƃ',
  36472. 'Æ„' => 'Æ…',
  36473. 'Ɔ' => 'ɔ',
  36474. 'Ƈ' => 'ƈ',
  36475. 'Ɖ' => 'ɖ',
  36476. 'ÆŠ' => 'É—',
  36477. 'Ƌ' => 'ƌ',
  36478. 'Ǝ' => '�',
  36479. '�' => 'ə',
  36480. '�' => 'ɛ',
  36481. 'Æ‘' => 'Æ’',
  36482. 'Æ“' => 'É ',
  36483. 'Æ”' => 'É£',
  36484. 'Æ–' => 'É©',
  36485. 'Ɨ' => 'ɨ',
  36486. 'Ƙ' => 'ƙ',
  36487. 'Ɯ' => 'ɯ',
  36488. '�' => 'ɲ',
  36489. 'Ɵ' => 'ɵ',
  36490. 'Æ ' => 'Æ¡',
  36491. 'Æ¢' => 'Æ£',
  36492. 'Ƥ' => 'ƥ',
  36493. 'Ʀ' => 'ʀ',
  36494. 'Ƨ' => 'ƨ',
  36495. 'Ʃ' => 'ʃ',
  36496. 'Ƭ' => 'ƭ',
  36497. 'Ʈ' => 'ʈ',
  36498. 'Ư' => 'ư',
  36499. 'Ʊ' => 'ʊ',
  36500. 'Ʋ' => 'ʋ',
  36501. 'Ƴ' => 'ƴ',
  36502. 'Ƶ' => 'ƶ',
  36503. 'Æ·' => 'Ê’',
  36504. 'Ƹ' => 'ƹ',
  36505. 'Ƽ' => 'ƽ',
  36506. 'DŽ' => 'dž',
  36507. 'Dž' => 'dž',
  36508. 'LJ' => 'lj',
  36509. 'Lj' => 'lj',
  36510. 'NJ' => 'nj',
  36511. 'Nj' => 'nj',
  36512. '�' => 'ǎ',
  36513. '�' => '�',
  36514. 'Ç‘' => 'Ç’',
  36515. 'Ç“' => 'Ç”',
  36516. 'Ç•' => 'Ç–',
  36517. 'Ǘ' => 'ǘ',
  36518. 'Ç™' => 'Çš',
  36519. 'Ǜ' => 'ǜ',
  36520. 'Çž' => 'ÇŸ',
  36521. 'Ç ' => 'Ç¡',
  36522. 'Ç¢' => 'Ç£',
  36523. 'Ǥ' => 'ǥ',
  36524. 'Ǧ' => 'ǧ',
  36525. 'Ǩ' => 'ǩ',
  36526. 'Ǫ' => 'ǫ',
  36527. 'Ǭ' => 'ǭ',
  36528. 'Ǯ' => 'ǯ',
  36529. 'DZ' => 'dz',
  36530. 'Dz' => 'dz',
  36531. 'Ǵ' => 'ǵ',
  36532. 'Ƕ' => 'ƕ',
  36533. 'Ç·' => 'Æ¿',
  36534. 'Ǹ' => 'ǹ',
  36535. 'Ǻ' => 'ǻ',
  36536. 'Ǽ' => 'ǽ',
  36537. 'Ǿ' => 'ǿ',
  36538. 'Ȁ' => '�',
  36539. 'Ȃ' => 'ȃ',
  36540. 'È„' => 'È…',
  36541. 'Ȇ' => 'ȇ',
  36542. 'Ȉ' => 'ȉ',
  36543. 'ÈŠ' => 'È‹',
  36544. 'Ȍ' => '�',
  36545. 'Ȏ' => '�',
  36546. '�' => 'ȑ',
  36547. 'È’' => 'È“',
  36548. 'È”' => 'È•',
  36549. 'È–' => 'È—',
  36550. 'Ș' => 'ș',
  36551. 'Èš' => 'È›',
  36552. 'Ȝ' => '�',
  36553. 'Èž' => 'ÈŸ',
  36554. 'È ' => 'Æž',
  36555. 'È¢' => 'È£',
  36556. 'Ȥ' => 'ȥ',
  36557. 'Ȧ' => 'ȧ',
  36558. 'Ȩ' => 'ȩ',
  36559. 'Ȫ' => 'ȫ',
  36560. 'Ȭ' => 'ȭ',
  36561. 'Ȯ' => 'ȯ',
  36562. 'Ȱ' => 'ȱ',
  36563. 'Ȳ' => 'ȳ',
  36564. 'Ⱥ' => 'ⱥ',
  36565. 'Ȼ' => 'ȼ',
  36566. 'Ƚ' => 'ƚ',
  36567. 'Ⱦ' => 'ⱦ',
  36568. '�' => 'ɂ',
  36569. 'Ƀ' => 'ƀ',
  36570. 'Ʉ' => 'ʉ',
  36571. 'Ʌ' => 'ʌ',
  36572. 'Ɇ' => 'ɇ',
  36573. 'Ɉ' => 'ɉ',
  36574. 'ÉŠ' => 'É‹',
  36575. 'Ɍ' => '�',
  36576. 'Ɏ' => '�',
  36577. 'Ͱ' => 'ͱ',
  36578. 'Ͳ' => 'ͳ',
  36579. 'Ͷ' => 'ͷ',
  36580. 'Ϳ' => 'ϳ',
  36581. 'Ά' => 'ά',
  36582. 'Έ' => 'έ',
  36583. 'Ή' => 'ή',
  36584. 'Ί' => 'ί',
  36585. 'Ό' => 'ό',
  36586. 'Ύ' => '�',
  36587. '�' => 'ώ',
  36588. 'Α' => 'α',
  36589. 'Β' => 'β',
  36590. 'Γ' => 'γ',
  36591. 'Δ' => 'δ',
  36592. 'Ε' => 'ε',
  36593. 'Ζ' => 'ζ',
  36594. 'Η' => 'η',
  36595. 'Θ' => 'θ',
  36596. 'Ι' => 'ι',
  36597. 'Κ' => 'κ',
  36598. 'Λ' => 'λ',
  36599. 'Μ' => 'μ',
  36600. '�' => 'ν',
  36601. 'Ξ' => 'ξ',
  36602. 'Ο' => 'ο',
  36603. 'Π' => 'π',
  36604. 'Ρ' => '�',
  36605. 'Σ' => 'σ',
  36606. 'Τ' => 'τ',
  36607. 'Î¥' => 'Ï…',
  36608. 'Φ' => 'φ',
  36609. 'Χ' => 'χ',
  36610. 'Ψ' => 'ψ',
  36611. 'Ω' => 'ω',
  36612. 'Ϊ' => 'ϊ',
  36613. 'Ϋ' => 'ϋ',
  36614. '�' => 'ϗ',
  36615. 'Ϙ' => 'ϙ',
  36616. 'Ïš' => 'Ï›',
  36617. 'Ϝ' => '�',
  36618. 'Ïž' => 'ÏŸ',
  36619. 'Ï ' => 'Ï¡',
  36620. 'Ï¢' => 'Ï£',
  36621. 'Ϥ' => 'ϥ',
  36622. 'Ϧ' => 'ϧ',
  36623. 'Ϩ' => 'ϩ',
  36624. 'Ϫ' => 'ϫ',
  36625. 'Ϭ' => 'ϭ',
  36626. 'Ϯ' => 'ϯ',
  36627. 'ϴ' => 'θ',
  36628. 'Ϸ' => 'ϸ',
  36629. 'Ϲ' => 'ϲ',
  36630. 'Ϻ' => 'ϻ',
  36631. 'Ͻ' => 'ͻ',
  36632. 'Ͼ' => 'ͼ',
  36633. 'Ͽ' => 'ͽ',
  36634. 'Ѐ' => '�',
  36635. '�' => 'ё',
  36636. 'Ђ' => 'ђ',
  36637. 'Ѓ' => 'ѓ',
  36638. 'Є' => 'є',
  36639. 'Ð…' => 'Ñ•',
  36640. 'І' => 'і',
  36641. 'Ї' => 'ї',
  36642. 'Ј' => 'ј',
  36643. 'Љ' => 'љ',
  36644. 'Њ' => 'њ',
  36645. 'Ћ' => 'ћ',
  36646. 'Ќ' => 'ќ',
  36647. '�' => '�',
  36648. 'ÐŽ' => 'Ñž',
  36649. '�' => 'џ',
  36650. '�' => 'а',
  36651. 'Б' => 'б',
  36652. 'В' => 'в',
  36653. 'Г' => 'г',
  36654. 'Д' => 'д',
  36655. 'Е' => 'е',
  36656. 'Ж' => 'ж',
  36657. 'З' => 'з',
  36658. 'И' => 'и',
  36659. 'Й' => 'й',
  36660. 'К' => 'к',
  36661. 'Л' => 'л',
  36662. 'М' => 'м',
  36663. '�' => 'н',
  36664. 'О' => 'о',
  36665. 'П' => 'п',
  36666. 'Р' => 'р',
  36667. 'С' => '�',
  36668. 'Т' => 'т',
  36669. 'У' => 'у',
  36670. 'Ф' => 'ф',
  36671. 'Ð¥' => 'Ñ…',
  36672. 'Ц' => 'ц',
  36673. 'Ч' => 'ч',
  36674. 'Ш' => 'ш',
  36675. 'Щ' => 'щ',
  36676. 'Ъ' => 'ъ',
  36677. 'Ы' => 'ы',
  36678. 'Ь' => 'ь',
  36679. 'Э' => '�',
  36680. 'Ю' => 'ю',
  36681. 'Я' => '�',
  36682. 'Ñ ' => 'Ñ¡',
  36683. 'Ñ¢' => 'Ñ£',
  36684. 'Ѥ' => 'ѥ',
  36685. 'Ѧ' => 'ѧ',
  36686. 'Ѩ' => 'ѩ',
  36687. 'Ѫ' => 'ѫ',
  36688. 'Ѭ' => 'ѭ',
  36689. 'Ѯ' => 'ѯ',
  36690. 'Ѱ' => 'ѱ',
  36691. 'Ѳ' => 'ѳ',
  36692. 'Ѵ' => 'ѵ',
  36693. 'Ѷ' => 'ѷ',
  36694. 'Ѹ' => 'ѹ',
  36695. 'Ѻ' => 'ѻ',
  36696. 'Ѽ' => 'ѽ',
  36697. 'Ѿ' => 'ѿ',
  36698. 'Ò€' => 'Ò�',
  36699. 'ÒŠ' => 'Ò‹',
  36700. 'Ҍ' => '�',
  36701. 'ÒŽ' => 'Ò�',
  36702. 'Ò�' => 'Ò‘',
  36703. 'Ò’' => 'Ò“',
  36704. 'Ò”' => 'Ò•',
  36705. 'Ò–' => 'Ò—',
  36706. 'Ò˜' => 'Ò™',
  36707. 'Òš' => 'Ò›',
  36708. 'Ҝ' => '�',
  36709. 'Òž' => 'ÒŸ',
  36710. 'Ò ' => 'Ò¡',
  36711. 'Ò¢' => 'Ò£',
  36712. 'Ò¤' => 'Ò¥',
  36713. 'Ò¦' => 'Ò§',
  36714. 'Ò¨' => 'Ò©',
  36715. 'Òª' => 'Ò«',
  36716. 'Ò¬' => 'Ò­',
  36717. 'Ò®' => 'Ò¯',
  36718. 'Ò°' => 'Ò±',
  36719. 'Ò²' => 'Ò³',
  36720. 'Ò´' => 'Òµ',
  36721. 'Ò¶' => 'Ò·',
  36722. 'Ò¸' => 'Ò¹',
  36723. 'Òº' => 'Ò»',
  36724. 'Ò¼' => 'Ò½',
  36725. 'Ò¾' => 'Ò¿',
  36726. 'Ó€' => 'Ó�',
  36727. 'Ó�' => 'Ó‚',
  36728. 'Óƒ' => 'Ó„',
  36729. 'Ó…' => 'Ó†',
  36730. 'Ó‡' => 'Óˆ',
  36731. 'Ó‰' => 'ÓŠ',
  36732. 'Ӌ' => 'ӌ',
  36733. 'Ó�' => 'ÓŽ',
  36734. 'Ó�' => 'Ó‘',
  36735. 'Ó’' => 'Ó“',
  36736. 'Ó”' => 'Ó•',
  36737. 'Ó–' => 'Ó—',
  36738. 'Ó˜' => 'Ó™',
  36739. 'Óš' => 'Ó›',
  36740. 'Ӝ' => '�',
  36741. 'Óž' => 'ÓŸ',
  36742. 'Ó ' => 'Ó¡',
  36743. 'Ó¢' => 'Ó£',
  36744. 'Ó¤' => 'Ó¥',
  36745. 'Ó¦' => 'Ó§',
  36746. 'Ó¨' => 'Ó©',
  36747. 'Óª' => 'Ó«',
  36748. 'Ó¬' => 'Ó­',
  36749. 'Ó®' => 'Ó¯',
  36750. 'Ó°' => 'Ó±',
  36751. 'Ó²' => 'Ó³',
  36752. 'Ó´' => 'Óµ',
  36753. 'Ó¶' => 'Ó·',
  36754. 'Ó¸' => 'Ó¹',
  36755. 'Óº' => 'Ó»',
  36756. 'Ó¼' => 'Ó½',
  36757. 'Ó¾' => 'Ó¿',
  36758. 'Ô€' => 'Ô�',
  36759. 'Ô‚' => 'Ôƒ',
  36760. 'Ô„' => 'Ô…',
  36761. 'Ô†' => 'Ô‡',
  36762. 'Ôˆ' => 'Ô‰',
  36763. 'ÔŠ' => 'Ô‹',
  36764. 'Ԍ' => '�',
  36765. 'ÔŽ' => 'Ô�',
  36766. 'Ô�' => 'Ô‘',
  36767. 'Ô’' => 'Ô“',
  36768. 'Ô”' => 'Ô•',
  36769. 'Ô–' => 'Ô—',
  36770. 'Ô˜' => 'Ô™',
  36771. 'Ôš' => 'Ô›',
  36772. 'Ԝ' => '�',
  36773. 'Ôž' => 'ÔŸ',
  36774. 'Ô ' => 'Ô¡',
  36775. 'Ô¢' => 'Ô£',
  36776. 'Ô¤' => 'Ô¥',
  36777. 'Ô¦' => 'Ô§',
  36778. 'Ô¨' => 'Ô©',
  36779. 'Ôª' => 'Ô«',
  36780. 'Ô¬' => 'Ô­',
  36781. 'Ô®' => 'Ô¯',
  36782. 'Ô±' => 'Õ¡',
  36783. 'Ô²' => 'Õ¢',
  36784. 'Ô³' => 'Õ£',
  36785. 'Ô´' => 'Õ¤',
  36786. 'Ôµ' => 'Õ¥',
  36787. 'Ô¶' => 'Õ¦',
  36788. 'Ô·' => 'Õ§',
  36789. 'Ô¸' => 'Õ¨',
  36790. 'Ô¹' => 'Õ©',
  36791. 'Ôº' => 'Õª',
  36792. 'Ô»' => 'Õ«',
  36793. 'Ô¼' => 'Õ¬',
  36794. 'Ô½' => 'Õ­',
  36795. 'Ô¾' => 'Õ®',
  36796. 'Ô¿' => 'Õ¯',
  36797. 'Õ€' => 'Õ°',
  36798. 'Õ�' => 'Õ±',
  36799. 'Õ‚' => 'Õ²',
  36800. 'Õƒ' => 'Õ³',
  36801. 'Õ„' => 'Õ´',
  36802. 'Õ…' => 'Õµ',
  36803. 'Õ†' => 'Õ¶',
  36804. 'Õ‡' => 'Õ·',
  36805. 'Õˆ' => 'Õ¸',
  36806. 'Õ‰' => 'Õ¹',
  36807. 'ÕŠ' => 'Õº',
  36808. 'Õ‹' => 'Õ»',
  36809. 'Ռ' => 'ռ',
  36810. 'Õ�' => 'Õ½',
  36811. 'ÕŽ' => 'Õ¾',
  36812. 'Õ�' => 'Õ¿',
  36813. 'Õ�' => 'Ö€',
  36814. 'Õ‘' => 'Ö�',
  36815. 'Õ’' => 'Ö‚',
  36816. 'Õ“' => 'Öƒ',
  36817. 'Õ”' => 'Ö„',
  36818. 'Õ•' => 'Ö…',
  36819. 'Õ–' => 'Ö†',
  36820. 'á‚ ' => 'â´€',
  36821. 'á‚¡' => 'â´�',
  36822. 'á‚¢' => 'â´‚',
  36823. 'á‚£' => 'â´ƒ',
  36824. 'Ⴄ' => 'ⴄ',
  36825. 'á‚¥' => 'â´…',
  36826. 'Ⴆ' => 'ⴆ',
  36827. 'á‚§' => 'â´‡',
  36828. 'Ⴈ' => 'ⴈ',
  36829. 'á‚©' => 'â´‰',
  36830. 'Ⴊ' => 'ⴊ',
  36831. 'á‚«' => 'â´‹',
  36832. 'Ⴌ' => 'ⴌ',
  36833. 'á‚­' => 'â´�',
  36834. 'á‚®' => 'â´Ž',
  36835. 'Ⴏ' => '�',
  36836. 'á‚°' => 'â´�',
  36837. 'Ⴑ' => 'ⴑ',
  36838. 'Ⴒ' => 'ⴒ',
  36839. 'Ⴓ' => 'ⴓ',
  36840. 'á‚´' => 'â´”',
  36841. 'Ⴕ' => 'ⴕ',
  36842. 'á‚¶' => 'â´–',
  36843. 'á‚·' => 'â´—',
  36844. 'Ⴘ' => 'ⴘ',
  36845. 'Ⴙ' => 'ⴙ',
  36846. 'Ⴚ' => 'ⴚ',
  36847. 'á‚»' => 'â´›',
  36848. 'Ⴜ' => 'ⴜ',
  36849. 'Ⴝ' => '�',
  36850. 'Ⴞ' => 'ⴞ',
  36851. 'á‚¿' => 'â´Ÿ',
  36852. 'Ⴠ' => 'ⴠ',
  36853. '�' => 'ⴡ',
  36854. 'Ⴢ' => 'ⴢ',
  36855. 'Ⴣ' => 'ⴣ',
  36856. 'Ⴤ' => 'ⴤ',
  36857. 'Ⴥ' => 'ⴥ',
  36858. 'Ⴧ' => 'ⴧ',
  36859. '�' => 'ⴭ',
  36860. 'Ꭰ' => 'ꭰ',
  36861. 'Ꭱ' => 'ꭱ',
  36862. 'Ꭲ' => 'ꭲ',
  36863. 'Ꭳ' => 'ꭳ',
  36864. 'Ꭴ' => 'ꭴ',
  36865. 'Ꭵ' => 'ꭵ',
  36866. 'Ꭶ' => 'ꭶ',
  36867. 'Ꭷ' => 'ꭷ',
  36868. 'Ꭸ' => 'ꭸ',
  36869. 'Ꭹ' => 'ꭹ',
  36870. 'Ꭺ' => 'ꭺ',
  36871. 'Ꭻ' => 'ꭻ',
  36872. 'Ꭼ' => 'ꭼ',
  36873. 'Ꭽ' => 'ꭽ',
  36874. 'Ꭾ' => 'ꭾ',
  36875. 'Ꭿ' => 'ꭿ',
  36876. 'Ꮀ' => 'ꮀ',
  36877. 'Ꮁ' => '�',
  36878. 'Ꮂ' => 'ꮂ',
  36879. 'Ꮃ' => 'ꮃ',
  36880. 'Ꮄ' => 'ꮄ',
  36881. 'Ꮅ' => 'ꮅ',
  36882. 'Ꮆ' => 'ꮆ',
  36883. 'Ꮇ' => 'ꮇ',
  36884. 'Ꮈ' => 'ꮈ',
  36885. 'Ꮉ' => 'ꮉ',
  36886. 'Ꮊ' => 'ꮊ',
  36887. 'Ꮋ' => 'ꮋ',
  36888. 'Ꮌ' => 'ꮌ',
  36889. 'Ꮍ' => '�',
  36890. 'Ꮎ' => 'ꮎ',
  36891. 'Ꮏ' => '�',
  36892. '�' => '�',
  36893. '�' => 'ꮑ',
  36894. '�' => 'ꮒ',
  36895. '�' => 'ꮓ',
  36896. '�' => 'ꮔ',
  36897. '�' => 'ꮕ',
  36898. '�' => 'ꮖ',
  36899. '�' => 'ꮗ',
  36900. '�' => 'ꮘ',
  36901. '�' => 'ꮙ',
  36902. '�' => 'ꮚ',
  36903. '�' => 'ꮛ',
  36904. '�' => 'ꮜ',
  36905. '�' => '�',
  36906. '�' => 'ꮞ',
  36907. '�' => 'ꮟ',
  36908. '�' => 'ꮠ',
  36909. '�' => 'ꮡ',
  36910. '�' => 'ꮢ',
  36911. '�' => 'ꮣ',
  36912. '�' => 'ꮤ',
  36913. '�' => 'ꮥ',
  36914. '�' => 'ꮦ',
  36915. '�' => 'ꮧ',
  36916. '�' => 'ꮨ',
  36917. '�' => 'ꮩ',
  36918. '�' => 'ꮪ',
  36919. '�' => 'ꮫ',
  36920. '�' => 'ꮬ',
  36921. '�' => 'ꮭ',
  36922. '�' => 'ꮮ',
  36923. '�' => 'ꮯ',
  36924. '�' => 'ꮰ',
  36925. '�' => 'ꮱ',
  36926. '�' => 'ꮲ',
  36927. '�' => 'ꮳ',
  36928. '�' => 'ꮴ',
  36929. '�' => 'ꮵ',
  36930. '�' => 'ꮶ',
  36931. '�' => 'ꮷ',
  36932. '�' => 'ꮸ',
  36933. '�' => 'ꮹ',
  36934. '�' => 'ꮺ',
  36935. '�' => 'ꮻ',
  36936. '�' => 'ꮼ',
  36937. '�' => 'ꮽ',
  36938. '�' => 'ꮾ',
  36939. '�' => 'ꮿ',
  36940. '�' => '�',
  36941. '�' => '�',
  36942. '�' => '�',
  36943. '�' => '�',
  36944. '�' => '�',
  36945. '�' => '�',
  36946. '�' => '�',
  36947. 'Ბ' => 'ბ',
  36948. 'Გ' => 'გ',
  36949. 'Დ' => 'დ',
  36950. 'Ე' => 'ე',
  36951. 'Ვ' => 'ვ',
  36952. 'Ზ' => 'ზ',
  36953. 'Თ' => 'თ',
  36954. 'Ი' => 'ი',
  36955. 'Კ' => 'კ',
  36956. 'Ლ' => 'ლ',
  36957. 'Მ' => 'მ',
  36958. 'Ნ' => 'ნ',
  36959. '�' => '�',
  36960. 'Პ' => 'პ',
  36961. 'Ჟ' => 'ჟ',
  36962. 'Რ' => 'რ',
  36963. 'Ს' => 'ს',
  36964. 'Ტ' => 'ტ',
  36965. 'Უ' => 'უ',
  36966. 'Ფ' => 'ფ',
  36967. 'Ქ' => 'ქ',
  36968. 'Ღ' => 'ღ',
  36969. 'Ყ' => 'ყ',
  36970. 'Შ' => 'შ',
  36971. 'Ჩ' => 'ჩ',
  36972. 'Ც' => 'ც',
  36973. 'Ძ' => 'ძ',
  36974. 'Წ' => 'წ',
  36975. 'Ჭ' => 'ჭ',
  36976. 'Ხ' => 'ხ',
  36977. 'Ჯ' => 'ჯ',
  36978. 'Ჰ' => 'ჰ',
  36979. 'Ჱ' => 'ჱ',
  36980. 'Ჲ' => 'ჲ',
  36981. 'Ჳ' => 'ჳ',
  36982. 'Ჴ' => 'ჴ',
  36983. 'Ჵ' => 'ჵ',
  36984. 'Ჶ' => 'ჶ',
  36985. 'Ჷ' => 'ჷ',
  36986. 'Ჸ' => 'ჸ',
  36987. 'Ჹ' => 'ჹ',
  36988. 'Ჺ' => 'ჺ',
  36989. 'Ჽ' => 'ჽ',
  36990. 'Ჾ' => 'ჾ',
  36991. 'Ჿ' => 'ჿ',
  36992. 'Ḁ' => '�',
  36993. 'Ḃ' => 'ḃ',
  36994. 'Ḅ' => 'ḅ',
  36995. 'Ḇ' => 'ḇ',
  36996. 'Ḉ' => 'ḉ',
  36997. 'Ḋ' => 'ḋ',
  36998. 'Ḍ' => '�',
  36999. 'Ḏ' => '�',
  37000. '�' => 'ḑ',
  37001. 'Ḓ' => 'ḓ',
  37002. 'Ḕ' => 'ḕ',
  37003. 'Ḗ' => 'ḗ',
  37004. 'Ḙ' => 'ḙ',
  37005. 'Ḛ' => 'ḛ',
  37006. 'Ḝ' => '�',
  37007. 'Ḟ' => 'ḟ',
  37008. 'Ḡ' => 'ḡ',
  37009. 'Ḣ' => 'ḣ',
  37010. 'Ḥ' => 'ḥ',
  37011. 'Ḧ' => 'ḧ',
  37012. 'Ḩ' => 'ḩ',
  37013. 'Ḫ' => 'ḫ',
  37014. 'Ḭ' => 'ḭ',
  37015. 'Ḯ' => 'ḯ',
  37016. 'Ḱ' => 'ḱ',
  37017. 'Ḳ' => 'ḳ',
  37018. 'Ḵ' => 'ḵ',
  37019. 'Ḷ' => 'ḷ',
  37020. 'Ḹ' => 'ḹ',
  37021. 'Ḻ' => 'ḻ',
  37022. 'Ḽ' => 'ḽ',
  37023. 'Ḿ' => 'ḿ',
  37024. 'Ṁ' => '�',
  37025. 'Ṃ' => 'ṃ',
  37026. 'Ṅ' => 'ṅ',
  37027. 'Ṇ' => 'ṇ',
  37028. 'Ṉ' => 'ṉ',
  37029. 'Ṋ' => 'ṋ',
  37030. 'Ṍ' => '�',
  37031. 'Ṏ' => '�',
  37032. '�' => 'ṑ',
  37033. 'Ṓ' => 'ṓ',
  37034. 'Ṕ' => 'ṕ',
  37035. 'á¹–' => 'á¹—',
  37036. 'Ṙ' => 'ṙ',
  37037. 'Ṛ' => 'ṛ',
  37038. 'Ṝ' => '�',
  37039. 'Ṟ' => 'ṟ',
  37040. 'Ṡ' => 'ṡ',
  37041. 'á¹¢' => 'á¹£',
  37042. 'Ṥ' => 'ṥ',
  37043. 'Ṧ' => 'ṧ',
  37044. 'Ṩ' => 'ṩ',
  37045. 'Ṫ' => 'ṫ',
  37046. 'Ṭ' => 'ṭ',
  37047. 'Ṯ' => 'ṯ',
  37048. 'á¹°' => 'á¹±',
  37049. 'á¹²' => 'á¹³',
  37050. 'á¹´' => 'á¹µ',
  37051. 'á¹¶' => 'á¹·',
  37052. 'Ṹ' => 'ṹ',
  37053. 'Ṻ' => 'ṻ',
  37054. 'á¹¼' => 'á¹½',
  37055. 'Ṿ' => 'ṿ',
  37056. 'Ẁ' => '�',
  37057. 'Ẃ' => 'ẃ',
  37058. 'Ẅ' => 'ẅ',
  37059. 'Ẇ' => 'ẇ',
  37060. 'Ẉ' => 'ẉ',
  37061. 'Ẋ' => 'ẋ',
  37062. 'Ẍ' => '�',
  37063. 'Ẏ' => '�',
  37064. '�' => 'ẑ',
  37065. 'Ẓ' => 'ẓ',
  37066. 'Ẕ' => 'ẕ',
  37067. 'ẞ' => 'ß',
  37068. 'Ạ' => 'ạ',
  37069. 'Ả' => 'ả',
  37070. 'Ấ' => 'ấ',
  37071. 'Ầ' => 'ầ',
  37072. 'Ẩ' => 'ẩ',
  37073. 'Ẫ' => 'ẫ',
  37074. 'Ậ' => 'ậ',
  37075. 'Ắ' => 'ắ',
  37076. 'Ằ' => 'ằ',
  37077. 'Ẳ' => 'ẳ',
  37078. 'Ẵ' => 'ẵ',
  37079. 'Ặ' => 'ặ',
  37080. 'Ẹ' => 'ẹ',
  37081. 'Ẻ' => 'ẻ',
  37082. 'Ẽ' => 'ẽ',
  37083. 'Ế' => 'ế',
  37084. 'Ề' => '�',
  37085. 'Ể' => 'ể',
  37086. 'Ễ' => 'ễ',
  37087. 'Ệ' => 'ệ',
  37088. 'Ỉ' => 'ỉ',
  37089. 'Ị' => 'ị',
  37090. 'Ọ' => '�',
  37091. 'Ỏ' => '�',
  37092. '�' => 'ố',
  37093. 'Ồ' => 'ồ',
  37094. 'Ổ' => 'ổ',
  37095. 'á»–' => 'á»—',
  37096. 'Ộ' => 'ộ',
  37097. 'Ớ' => 'ớ',
  37098. 'Ờ' => '�',
  37099. 'Ở' => 'ở',
  37100. 'Ỡ' => 'ỡ',
  37101. 'Ợ' => 'ợ',
  37102. 'Ụ' => 'ụ',
  37103. 'Ủ' => 'ủ',
  37104. 'Ứ' => 'ứ',
  37105. 'Ừ' => 'ừ',
  37106. 'Ử' => 'ử',
  37107. 'Ữ' => 'ữ',
  37108. 'á»°' => 'á»±',
  37109. 'Ỳ' => 'ỳ',
  37110. 'Ỵ' => 'ỵ',
  37111. 'á»¶' => 'á»·',
  37112. 'Ỹ' => 'ỹ',
  37113. 'Ỻ' => 'ỻ',
  37114. 'Ỽ' => 'ỽ',
  37115. 'Ỿ' => 'ỿ',
  37116. 'Ἀ' => 'ἀ',
  37117. 'Ἁ' => '�',
  37118. 'Ἂ' => 'ἂ',
  37119. 'Ἃ' => 'ἃ',
  37120. 'Ἄ' => 'ἄ',
  37121. '�' => 'ἅ',
  37122. 'Ἆ' => 'ἆ',
  37123. '�' => 'ἇ',
  37124. 'Ἐ' => '�',
  37125. 'Ἑ' => 'ἑ',
  37126. 'Ἒ' => 'ἒ',
  37127. 'Ἓ' => 'ἓ',
  37128. 'Ἔ' => 'ἔ',
  37129. '�' => 'ἕ',
  37130. 'Ἠ' => 'ἠ',
  37131. 'Ἡ' => 'ἡ',
  37132. 'Ἢ' => 'ἢ',
  37133. 'Ἣ' => 'ἣ',
  37134. 'Ἤ' => 'ἤ',
  37135. 'á¼­' => 'á¼¥',
  37136. 'Ἦ' => 'ἦ',
  37137. 'Ἧ' => 'ἧ',
  37138. 'Ἰ' => 'ἰ',
  37139. 'á¼¹' => 'á¼±',
  37140. 'Ἲ' => 'ἲ',
  37141. 'á¼»' => 'á¼³',
  37142. 'á¼¼' => 'á¼´',
  37143. 'á¼½' => 'á¼µ',
  37144. 'á¼¾' => 'á¼¶',
  37145. 'Ἷ' => 'ἷ',
  37146. 'Ὀ' => 'ὀ',
  37147. 'Ὁ' => '�',
  37148. 'Ὂ' => 'ὂ',
  37149. 'Ὃ' => 'ὃ',
  37150. 'Ὄ' => 'ὄ',
  37151. '�' => 'ὅ',
  37152. 'Ὑ' => 'ὑ',
  37153. 'Ὓ' => 'ὓ',
  37154. '�' => 'ὕ',
  37155. 'Ὗ' => 'ὗ',
  37156. 'Ὠ' => 'ὠ',
  37157. 'Ὡ' => 'ὡ',
  37158. 'Ὢ' => 'ὢ',
  37159. 'Ὣ' => 'ὣ',
  37160. 'Ὤ' => 'ὤ',
  37161. 'á½­' => 'á½¥',
  37162. 'Ὦ' => 'ὦ',
  37163. 'Ὧ' => 'ὧ',
  37164. 'ᾈ' => 'ᾀ',
  37165. 'ᾉ' => '�',
  37166. 'ᾊ' => 'ᾂ',
  37167. 'ᾋ' => 'ᾃ',
  37168. 'ᾌ' => 'ᾄ',
  37169. '�' => 'ᾅ',
  37170. 'ᾎ' => 'ᾆ',
  37171. '�' => 'ᾇ',
  37172. 'ᾘ' => '�',
  37173. 'ᾙ' => 'ᾑ',
  37174. 'ᾚ' => 'ᾒ',
  37175. 'ᾛ' => 'ᾓ',
  37176. 'ᾜ' => 'ᾔ',
  37177. '�' => 'ᾕ',
  37178. 'ᾞ' => 'ᾖ',
  37179. 'ᾟ' => 'ᾗ',
  37180. 'ᾨ' => 'ᾠ',
  37181. 'ᾩ' => 'ᾡ',
  37182. 'ᾪ' => 'ᾢ',
  37183. 'ᾫ' => 'ᾣ',
  37184. 'ᾬ' => 'ᾤ',
  37185. 'á¾­' => 'á¾¥',
  37186. 'ᾮ' => 'ᾦ',
  37187. 'ᾯ' => 'ᾧ',
  37188. 'Ᾰ' => 'ᾰ',
  37189. 'á¾¹' => 'á¾±',
  37190. 'Ὰ' => 'ὰ',
  37191. 'á¾»' => 'á½±',
  37192. 'á¾¼' => 'á¾³',
  37193. 'Ὲ' => 'ὲ',
  37194. 'Έ' => 'έ',
  37195. 'Ὴ' => 'ὴ',
  37196. 'á¿‹' => 'á½µ',
  37197. 'ῌ' => 'ῃ',
  37198. 'Ῐ' => '�',
  37199. 'á¿™' => 'á¿‘',
  37200. 'Ὶ' => 'ὶ',
  37201. 'á¿›' => 'á½·',
  37202. 'Ῠ' => 'ῠ',
  37203. 'á¿©' => 'á¿¡',
  37204. 'Ὺ' => 'ὺ',
  37205. 'á¿«' => 'á½»',
  37206. 'Ῥ' => 'ῥ',
  37207. 'Ὸ' => 'ὸ',
  37208. 'Ό' => 'ό',
  37209. 'Ὼ' => 'ὼ',
  37210. 'á¿»' => 'á½½',
  37211. 'ῼ' => 'ῳ',
  37212. 'Ω' => 'ω',
  37213. 'K' => 'k',
  37214. 'â„«' => 'Ã¥',
  37215. 'Ⅎ' => 'ⅎ',
  37216. 'â… ' => 'â…°',
  37217. 'â…¡' => 'â…±',
  37218. 'â…¢' => 'â…²',
  37219. 'â…£' => 'â…³',
  37220. 'â…¤' => 'â…´',
  37221. 'â…¥' => 'â…µ',
  37222. 'â…¦' => 'â…¶',
  37223. 'â…§' => 'â…·',
  37224. 'â…¨' => 'â…¸',
  37225. 'â…©' => 'â…¹',
  37226. 'â…ª' => 'â…º',
  37227. 'â…«' => 'â…»',
  37228. 'â…¬' => 'â…¼',
  37229. 'â…­' => 'â…½',
  37230. 'â…®' => 'â…¾',
  37231. 'â…¯' => 'â…¿',
  37232. 'Ↄ' => 'ↄ',
  37233. 'Ⓐ' => '�',
  37234. 'â’·' => 'â“‘',
  37235. 'â’¸' => 'â“’',
  37236. 'â’¹' => 'â““',
  37237. 'â’º' => 'â“”',
  37238. 'â’»' => 'â“•',
  37239. 'â’¼' => 'â“–',
  37240. 'â’½' => 'â“—',
  37241. 'Ⓘ' => 'ⓘ',
  37242. 'â’¿' => 'â“™',
  37243. 'Ⓚ' => 'ⓚ',
  37244. '�' => 'ⓛ',
  37245. 'Ⓜ' => 'ⓜ',
  37246. 'Ⓝ' => '�',
  37247. 'Ⓞ' => 'ⓞ',
  37248. 'Ⓟ' => 'ⓟ',
  37249. 'Ⓠ' => 'ⓠ',
  37250. 'Ⓡ' => 'ⓡ',
  37251. 'Ⓢ' => 'ⓢ',
  37252. 'Ⓣ' => 'ⓣ',
  37253. 'Ⓤ' => 'ⓤ',
  37254. 'â“‹' => 'â“¥',
  37255. 'Ⓦ' => 'ⓦ',
  37256. '�' => 'ⓧ',
  37257. 'Ⓨ' => 'ⓨ',
  37258. '�' => 'ⓩ',
  37259. 'â°€' => 'â°°',
  37260. 'â°�' => 'â°±',
  37261. 'â°‚' => 'â°²',
  37262. 'â°ƒ' => 'â°³',
  37263. 'â°„' => 'â°´',
  37264. 'â°…' => 'â°µ',
  37265. 'â°†' => 'â°¶',
  37266. 'â°‡' => 'â°·',
  37267. 'â°ˆ' => 'â°¸',
  37268. 'â°‰' => 'â°¹',
  37269. 'â°Š' => 'â°º',
  37270. 'â°‹' => 'â°»',
  37271. 'Ⰼ' => 'ⰼ',
  37272. 'â°�' => 'â°½',
  37273. 'â°Ž' => 'â°¾',
  37274. 'â°�' => 'â°¿',
  37275. 'â°�' => 'â±€',
  37276. 'Ⱁ' => '�',
  37277. 'Ⱂ' => 'ⱂ',
  37278. 'Ⱃ' => 'ⱃ',
  37279. 'Ⱄ' => 'ⱄ',
  37280. 'â°•' => 'â±…',
  37281. 'Ⱆ' => 'ⱆ',
  37282. 'Ⱇ' => 'ⱇ',
  37283. 'Ⱈ' => 'ⱈ',
  37284. 'Ⱉ' => 'ⱉ',
  37285. 'Ⱊ' => 'ⱊ',
  37286. 'Ⱋ' => 'ⱋ',
  37287. 'Ⱌ' => 'ⱌ',
  37288. '�' => '�',
  37289. 'Ⱎ' => 'ⱎ',
  37290. 'Ⱏ' => '�',
  37291. 'Ⱐ' => '�',
  37292. 'Ⱑ' => 'ⱑ',
  37293. 'â°¢' => 'â±’',
  37294. 'Ⱓ' => 'ⱓ',
  37295. 'â°¤' => 'â±”',
  37296. 'Ⱕ' => 'ⱕ',
  37297. 'â°¦' => 'â±–',
  37298. 'â°§' => 'â±—',
  37299. 'Ⱘ' => 'ⱘ',
  37300. 'â°©' => 'â±™',
  37301. 'Ⱚ' => 'ⱚ',
  37302. 'â°«' => 'â±›',
  37303. 'Ⱜ' => 'ⱜ',
  37304. 'Ⱝ' => '�',
  37305. 'Ⱞ' => 'ⱞ',
  37306. 'Ⱡ' => 'ⱡ',
  37307. 'â±¢' => 'É«',
  37308. 'â±£' => 'áµ½',
  37309. 'Ɽ' => 'ɽ',
  37310. 'Ⱨ' => 'ⱨ',
  37311. 'Ⱪ' => 'ⱪ',
  37312. 'Ⱬ' => 'ⱬ',
  37313. 'â±­' => 'É‘',
  37314. 'Ɱ' => 'ɱ',
  37315. 'Ɐ' => '�',
  37316. 'â±°' => 'É’',
  37317. 'â±²' => 'â±³',
  37318. 'â±µ' => 'â±¶',
  37319. 'â±¾' => 'È¿',
  37320. 'Ɀ' => 'ɀ',
  37321. 'Ⲁ' => '�',
  37322. 'Ⲃ' => 'ⲃ',
  37323. 'Ⲅ' => 'ⲅ',
  37324. 'Ⲇ' => 'ⲇ',
  37325. 'Ⲉ' => 'ⲉ',
  37326. 'Ⲋ' => 'ⲋ',
  37327. 'Ⲍ' => '�',
  37328. 'Ⲏ' => '�',
  37329. '�' => 'ⲑ',
  37330. 'Ⲓ' => 'ⲓ',
  37331. 'Ⲕ' => 'ⲕ',
  37332. 'â²–' => 'â²—',
  37333. 'Ⲙ' => 'ⲙ',
  37334. 'Ⲛ' => 'ⲛ',
  37335. 'Ⲝ' => '�',
  37336. 'Ⲟ' => 'ⲟ',
  37337. 'Ⲡ' => 'ⲡ',
  37338. 'â²¢' => 'â²£',
  37339. 'Ⲥ' => 'ⲥ',
  37340. 'Ⲧ' => 'ⲧ',
  37341. 'Ⲩ' => 'ⲩ',
  37342. 'Ⲫ' => 'ⲫ',
  37343. 'Ⲭ' => 'ⲭ',
  37344. 'Ⲯ' => 'ⲯ',
  37345. 'â²°' => 'â²±',
  37346. 'â²²' => 'â²³',
  37347. 'â²´' => 'â²µ',
  37348. 'â²¶' => 'â²·',
  37349. 'Ⲹ' => 'ⲹ',
  37350. 'Ⲻ' => 'ⲻ',
  37351. 'â²¼' => 'â²½',
  37352. 'Ⲿ' => 'ⲿ',
  37353. 'Ⳁ' => '�',
  37354. 'Ⳃ' => 'ⳃ',
  37355. 'Ⳅ' => 'ⳅ',
  37356. 'Ⳇ' => 'ⳇ',
  37357. 'Ⳉ' => 'ⳉ',
  37358. 'Ⳋ' => 'ⳋ',
  37359. 'Ⳍ' => '�',
  37360. 'Ⳏ' => '�',
  37361. '�' => 'ⳑ',
  37362. 'Ⳓ' => 'ⳓ',
  37363. 'Ⳕ' => 'ⳕ',
  37364. 'â³–' => 'â³—',
  37365. 'Ⳙ' => 'ⳙ',
  37366. 'Ⳛ' => 'ⳛ',
  37367. 'Ⳝ' => '�',
  37368. 'Ⳟ' => 'ⳟ',
  37369. 'Ⳡ' => 'ⳡ',
  37370. 'â³¢' => 'â³£',
  37371. 'Ⳬ' => 'ⳬ',
  37372. 'â³­' => 'â³®',
  37373. 'â³²' => 'â³³',
  37374. 'Ꙁ' => '�',
  37375. 'Ꙃ' => 'ꙃ',
  37376. 'Ꙅ' => 'ꙅ',
  37377. 'Ꙇ' => 'ꙇ',
  37378. 'Ꙉ' => 'ꙉ',
  37379. 'Ꙋ' => 'ꙋ',
  37380. 'Ꙍ' => '�',
  37381. 'Ꙏ' => '�',
  37382. '�' => 'ꙑ',
  37383. 'Ꙓ' => 'ꙓ',
  37384. 'Ꙕ' => 'ꙕ',
  37385. 'ê™–' => 'ê™—',
  37386. 'Ꙙ' => 'ꙙ',
  37387. 'Ꙛ' => 'ꙛ',
  37388. 'Ꙝ' => '�',
  37389. 'Ꙟ' => 'ꙟ',
  37390. 'Ꙡ' => 'ꙡ',
  37391. 'Ꙣ' => 'ꙣ',
  37392. 'Ꙥ' => 'ꙥ',
  37393. 'Ꙧ' => 'ꙧ',
  37394. 'Ꙩ' => 'ꙩ',
  37395. 'Ꙫ' => 'ꙫ',
  37396. 'Ꙭ' => 'ꙭ',
  37397. 'Ꚁ' => '�',
  37398. 'Ꚃ' => 'ꚃ',
  37399. 'êš„' => 'êš…',
  37400. 'Ꚇ' => 'ꚇ',
  37401. 'Ꚉ' => 'ꚉ',
  37402. 'Ꚋ' => 'ꚋ',
  37403. 'Ꚍ' => '�',
  37404. 'Ꚏ' => '�',
  37405. '�' => 'ꚑ',
  37406. 'êš’' => 'êš“',
  37407. 'êš”' => 'êš•',
  37408. 'êš–' => 'êš—',
  37409. 'Ꚙ' => 'ꚙ',
  37410. 'êšš' => 'êš›',
  37411. 'Ꜣ' => 'ꜣ',
  37412. 'Ꜥ' => 'ꜥ',
  37413. 'Ꜧ' => 'ꜧ',
  37414. 'Ꜩ' => 'ꜩ',
  37415. 'Ꜫ' => 'ꜫ',
  37416. 'Ꜭ' => 'ꜭ',
  37417. 'Ꜯ' => 'ꜯ',
  37418. 'Ꜳ' => 'ꜳ',
  37419. 'Ꜵ' => 'ꜵ',
  37420. 'Ꜷ' => 'ꜷ',
  37421. 'Ꜹ' => 'ꜹ',
  37422. 'Ꜻ' => 'ꜻ',
  37423. 'Ꜽ' => 'ꜽ',
  37424. 'Ꜿ' => 'ꜿ',
  37425. '�' => '�',
  37426. '�' => '�',
  37427. '�' => '�',
  37428. '�' => '�',
  37429. '�' => '�',
  37430. '�' => '�',
  37431. '�' => '�',
  37432. '�' => '�',
  37433. '�' => '�',
  37434. '�' => '�',
  37435. '�' => '�',
  37436. '�' => '�',
  37437. '�' => '�',
  37438. '�' => '�',
  37439. '�' => '�',
  37440. '�' => '�',
  37441. '�' => '�',
  37442. '�' => '�',
  37443. '�' => '�',
  37444. '�' => '�',
  37445. '�' => '�',
  37446. '�' => '�',
  37447. '�' => '�',
  37448. '�' => '�',
  37449. '�' => '�',
  37450. '�' => '�',
  37451. '�' => 'ᵹ',
  37452. '�' => '�',
  37453. 'Ꞁ' => '�',
  37454. 'Ꞃ' => 'ꞃ',
  37455. 'êž„' => 'êž…',
  37456. 'Ꞇ' => 'ꞇ',
  37457. 'Ꞌ' => 'ꞌ',
  37458. '�' => 'ɥ',
  37459. '�' => 'ꞑ',
  37460. 'êž’' => 'êž“',
  37461. 'êž–' => 'êž—',
  37462. 'Ꞙ' => 'ꞙ',
  37463. 'êžš' => 'êž›',
  37464. 'Ꞝ' => '�',
  37465. 'Ꞟ' => 'ꞟ',
  37466. 'êž ' => 'êž¡',
  37467. 'Ꞣ' => 'ꞣ',
  37468. 'Ꞥ' => 'ꞥ',
  37469. 'Ꞧ' => 'ꞧ',
  37470. 'Ꞩ' => 'ꞩ',
  37471. 'Ɦ' => 'ɦ',
  37472. 'Ɜ' => 'ɜ',
  37473. 'Ɡ' => 'ɡ',
  37474. 'Ɬ' => 'ɬ',
  37475. 'Ɪ' => 'ɪ',
  37476. 'êž°' => 'Êž',
  37477. 'Ʇ' => 'ʇ',
  37478. 'Ʝ' => '�',
  37479. 'êž³' => 'ê­“',
  37480. 'êž´' => 'êžµ',
  37481. 'êž¶' => 'êž·',
  37482. 'Ꞹ' => 'ꞹ',
  37483. 'Ꞻ' => 'ꞻ',
  37484. 'êž¼' => 'êž½',
  37485. 'êž¾' => 'êž¿',
  37486. 'Ꟃ' => 'ꟃ',
  37487. 'Ꞔ' => 'ꞔ',
  37488. 'Ʂ' => 'ʂ',
  37489. 'Ᶎ' => 'ᶎ',
  37490. 'Ꟈ' => 'ꟈ',
  37491. 'Ꟊ' => 'ꟊ',
  37492. 'Ꟶ' => 'ꟶ',
  37493. 'A' => '�',
  37494. 'B' => 'b',
  37495. 'C' => 'c',
  37496. 'D' => 'd',
  37497. 'ï¼¥' => 'ï½…',
  37498. 'F' => 'f',
  37499. 'G' => 'g',
  37500. 'H' => 'h',
  37501. 'I' => 'i',
  37502. 'J' => 'j',
  37503. 'K' => 'k',
  37504. 'L' => 'l',
  37505. 'M' => '�',
  37506. 'N' => 'n',
  37507. 'O' => '�',
  37508. 'P' => '�',
  37509. 'Q' => 'q',
  37510. 'ï¼²' => 'ï½’',
  37511. 'S' => 's',
  37512. 'ï¼´' => 'ï½”',
  37513. 'U' => 'u',
  37514. 'ï¼¶' => 'ï½–',
  37515. 'ï¼·' => 'ï½—',
  37516. 'X' => 'x',
  37517. 'ï¼¹' => 'ï½™',
  37518. 'Z' => 'z',
  37519. '�' => '�',
  37520. '�' => '�',
  37521. '�' => '�',
  37522. '�' => '�',
  37523. '�' => '�',
  37524. '�' => '�',
  37525. '�' => '�',
  37526. '�' => '�',
  37527. '�' => '�',
  37528. '�' => '�',
  37529. '�' => '�',
  37530. '�' => '�',
  37531. '�' => '�',
  37532. '�' => '�',
  37533. '�' => '�',
  37534. '�' => '�',
  37535. '�' => '�',
  37536. '�' => '�',
  37537. '�' => '�',
  37538. '�' => '�',
  37539. '�' => '�',
  37540. '�' => '�',
  37541. '�' => '�',
  37542. '�' => '�',
  37543. '�' => '�',
  37544. '�' => '�',
  37545. '�' => '�',
  37546. '�' => '�',
  37547. '�' => '�',
  37548. '�' => '�',
  37549. '�' => '�',
  37550. '�' => '�',
  37551. '�' => '�',
  37552. '�' => '�',
  37553. '�' => '�',
  37554. '�' => '�',
  37555. '�' => '�',
  37556. '�' => '�',
  37557. '�' => '�',
  37558. '�' => '�',
  37559. '�' => '�',
  37560. '�' => '�',
  37561. '�' => '�',
  37562. '�' => '�',
  37563. '�' => '�',
  37564. '�' => '�',
  37565. '�' => '�',
  37566. '�' => '�',
  37567. '�' => '�',
  37568. '�' => '�',
  37569. '�' => '�',
  37570. '�' => '�',
  37571. '�' => '�',
  37572. '�' => '�',
  37573. '�' => '�',
  37574. '�' => '�',
  37575. '�' => '�',
  37576. '�' => '�',
  37577. '�' => '�',
  37578. '�' => '�',
  37579. '�' => '�',
  37580. '�' => '�',
  37581. '�' => '�',
  37582. '�' => '�',
  37583. '�' => '�',
  37584. '�' => '�',
  37585. '�' => '�',
  37586. '�' => '�',
  37587. '�' => '�',
  37588. '�' => '�',
  37589. '�' => '�',
  37590. '�' => '�',
  37591. '�' => '�',
  37592. '�' => '�',
  37593. '�' => '�',
  37594. '�' => '�',
  37595. '�' => '�',
  37596. '�' => '�',
  37597. '�' => '�',
  37598. '�' => '�',
  37599. '�' => '�',
  37600. '�' => '�',
  37601. '�' => '�',
  37602. '�' => '�',
  37603. '�' => '�',
  37604. '�' => '�',
  37605. '�' => '�',
  37606. '�' => '�',
  37607. '�' => '�',
  37608. '�' => '�',
  37609. '�' => '�',
  37610. '�' => '�',
  37611. '�' => '�',
  37612. '�' => '�',
  37613. '�' => '�',
  37614. '�' => '�',
  37615. '�' => '�',
  37616. '�' => '�',
  37617. '�' => '�',
  37618. '�' => '�',
  37619. '�' => '�',
  37620. '�' => '�',
  37621. '�' => '�',
  37622. '�' => '�',
  37623. '�' => '�',
  37624. '�' => '�',
  37625. '�' => '�',
  37626. '�' => '�',
  37627. '�' => '�',
  37628. '�' => '�',
  37629. '�' => '�',
  37630. '�' => '�',
  37631. '�' => '�',
  37632. '�' => '�',
  37633. '�' => '�',
  37634. '�' => '�',
  37635. '�' => '�',
  37636. '�' => '�',
  37637. '�' => '�',
  37638. '�' => '�',
  37639. '�' => '�',
  37640. '�' => '�',
  37641. '�' => '�',
  37642. '�' => '�',
  37643. '�' => '�',
  37644. '�' => '�',
  37645. '�' => '�',
  37646. 'ð‘¢ ' => 'ð‘£€',
  37647. '𑢡' => '�',
  37648. '𑢢' => '𑣂',
  37649. '𑢣' => '𑣃',
  37650. '𑢤' => '𑣄',
  37651. 'ð‘¢¥' => 'ð‘£…',
  37652. '𑢦' => '𑣆',
  37653. '𑢧' => '𑣇',
  37654. '𑢨' => '𑣈',
  37655. '𑢩' => '𑣉',
  37656. '𑢪' => '𑣊',
  37657. '𑢫' => '𑣋',
  37658. '𑢬' => '𑣌',
  37659. '𑢭' => '�',
  37660. '𑢮' => '𑣎',
  37661. '𑢯' => '�',
  37662. '𑢰' => '�',
  37663. '𑢱' => '𑣑',
  37664. 'ð‘¢²' => 'ð‘£’',
  37665. '𑢳' => '𑣓',
  37666. 'ð‘¢´' => 'ð‘£”',
  37667. '𑢵' => '𑣕',
  37668. 'ð‘¢¶' => 'ð‘£–',
  37669. 'ð‘¢·' => 'ð‘£—',
  37670. '𑢸' => '𑣘',
  37671. 'ð‘¢¹' => 'ð‘£™',
  37672. '𑢺' => '𑣚',
  37673. 'ð‘¢»' => 'ð‘£›',
  37674. '𑢼' => '𑣜',
  37675. '𑢽' => '�',
  37676. '𑢾' => '𑣞',
  37677. '𑢿' => '𑣟',
  37678. 'ð–¹€' => 'ð–¹ ',
  37679. '�' => '𖹡',
  37680. '𖹂' => '𖹢',
  37681. '𖹃' => '𖹣',
  37682. '𖹄' => '𖹤',
  37683. 'ð–¹…' => 'ð–¹¥',
  37684. '𖹆' => '𖹦',
  37685. '𖹇' => '𖹧',
  37686. '𖹈' => '𖹨',
  37687. '𖹉' => '𖹩',
  37688. '𖹊' => '𖹪',
  37689. '𖹋' => '𖹫',
  37690. '𖹌' => '𖹬',
  37691. '�' => '𖹭',
  37692. '𖹎' => '𖹮',
  37693. '�' => '𖹯',
  37694. '�' => '𖹰',
  37695. '𖹑' => '𖹱',
  37696. 'ð–¹’' => 'ð–¹²',
  37697. '𖹓' => '𖹳',
  37698. 'ð–¹”' => 'ð–¹´',
  37699. '𖹕' => '𖹵',
  37700. 'ð–¹–' => 'ð–¹¶',
  37701. 'ð–¹—' => 'ð–¹·',
  37702. '𖹘' => '𖹸',
  37703. 'ð–¹™' => 'ð–¹¹',
  37704. '𖹚' => '𖹺',
  37705. 'ð–¹›' => 'ð–¹»',
  37706. '𖹜' => '𖹼',
  37707. '�' => '𖹽',
  37708. '𖹞' => '𖹾',
  37709. '𖹟' => '𖹿',
  37710. '𞤀' => '𞤢',
  37711. '�' => '𞤣',
  37712. '𞤂' => '𞤤',
  37713. '𞤃' => '𞤥',
  37714. '𞤄' => '𞤦',
  37715. '𞤅' => '𞤧',
  37716. '𞤆' => '𞤨',
  37717. '𞤇' => '𞤩',
  37718. '𞤈' => '𞤪',
  37719. '𞤉' => '𞤫',
  37720. '𞤊' => '𞤬',
  37721. '𞤋' => '𞤭',
  37722. '𞤌' => '𞤮',
  37723. '�' => '𞤯',
  37724. '𞤎' => '𞤰',
  37725. '�' => '𞤱',
  37726. '�' => '𞤲',
  37727. '𞤑' => '𞤳',
  37728. '𞤒' => '𞤴',
  37729. '𞤓' => '𞤵',
  37730. '𞤔' => '𞤶',
  37731. '𞤕' => '𞤷',
  37732. '𞤖' => '𞤸',
  37733. '𞤗' => '𞤹',
  37734. '𞤘' => '𞤺',
  37735. '𞤙' => '𞤻',
  37736. '𞤚' => '𞤼',
  37737. '𞤛' => '𞤽',
  37738. '𞤜' => '𞤾',
  37739. '�' => '𞤿',
  37740. '𞤞' => '𞥀',
  37741. '𞤟' => '�',
  37742. '𞤠' => '𞥂',
  37743. '𞤡' => '𞥃',
  37744. );
  37745. <?php
  37746. return '/(?<![\x{0027}\x{002E}\x{003A}\x{005E}\x{0060}\x{00A8}\x{00AD}\x{00AF}\x{00B4}\x{00B7}\x{00B8}\x{02B0}-\x{02C1}\x{02C2}-\x{02C5}\x{02C6}-\x{02D1}\x{02D2}-\x{02DF}\x{02E0}-\x{02E4}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EE}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037A}\x{0384}-\x{0385}\x{0387}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0559}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{05F4}\x{0600}-\x{0605}\x{0610}-\x{061A}\x{061C}\x{0640}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DD}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07FA}\x{07FD}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0971}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E46}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EB9}\x{0EBB}-\x{0EBC}\x{0EC6}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{10FC}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17D7}\x{17DD}\x{180B}-\x{180D}\x{180E}\x{1843}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AA7}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1C78}-\x{1C7D}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200F}\x{2018}\x{2019}\x{2024}\x{2027}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{2066}-\x{206F}\x{2071}\x{207F}\x{2090}-\x{209C}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2C7C}-\x{2C7D}\x{2CEF}-\x{2CF1}\x{2D6F}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E2F}\x{3005}\x{302A}-\x{302D}\x{3031}-\x{3035}\x{303B}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A67F}\x{A69C}-\x{A69D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A770}\x{A788}\x{A789}-\x{A78A}\x{A7F8}-\x{A7F9}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}\x{A9CF}\x{A9E5}\x{A9E6}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA70}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AADD}\x{AAEC}-\x{AAED}\x{AAF3}-\x{AAF4}\x{AAF6}\x{AB5B}\x{AB5C}-\x{AB5F}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FBB2}-\x{FBC1}\x{FE00}-\x{FE0F}\x{FE13}\x{FE20}-\x{FE2F}\x{FE52}\x{FE55}\x{FEFF}\x{FF07}\x{FF0E}\x{FF1A}\x{FF3E}\x{FF40}\x{FF70}\x{FF9E}-\x{FF9F}\x{FFE3}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{110BD}\x{110CD}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16B40}-\x{16B43}\x{16F8F}-\x{16F92}\x{16F93}-\x{16F9F}\x{16FE0}-\x{16FE1}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1F3FB}-\x{1F3FF}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}])(\pL)(\pL*+)/u';
  37747. <?php
  37748. return array (
  37749. 'a' => 'A',
  37750. 'b' => 'B',
  37751. 'c' => 'C',
  37752. 'd' => 'D',
  37753. 'e' => 'E',
  37754. 'f' => 'F',
  37755. 'g' => 'G',
  37756. 'h' => 'H',
  37757. 'i' => 'I',
  37758. 'j' => 'J',
  37759. 'k' => 'K',
  37760. 'l' => 'L',
  37761. 'm' => 'M',
  37762. 'n' => 'N',
  37763. 'o' => 'O',
  37764. 'p' => 'P',
  37765. 'q' => 'Q',
  37766. 'r' => 'R',
  37767. 's' => 'S',
  37768. 't' => 'T',
  37769. 'u' => 'U',
  37770. 'v' => 'V',
  37771. 'w' => 'W',
  37772. 'x' => 'X',
  37773. 'y' => 'Y',
  37774. 'z' => 'Z',
  37775. 'µ' => 'Μ',
  37776. 'à' => 'À',
  37777. 'á' => '�',
  37778. 'â' => 'Â',
  37779. 'ã' => 'Ã',
  37780. 'ä' => 'Ä',
  37781. 'Ã¥' => 'Ã…',
  37782. 'æ' => 'Æ',
  37783. 'ç' => 'Ç',
  37784. 'è' => 'È',
  37785. 'é' => 'É',
  37786. 'ê' => 'Ê',
  37787. 'ë' => 'Ë',
  37788. 'ì' => 'Ì',
  37789. 'í' => '�',
  37790. 'î' => 'Î',
  37791. 'ï' => '�',
  37792. 'ð' => '�',
  37793. 'ñ' => 'Ñ',
  37794. 'ò' => 'Ò',
  37795. 'ó' => 'Ó',
  37796. 'ô' => 'Ô',
  37797. 'õ' => 'Õ',
  37798. 'ö' => 'Ö',
  37799. 'ø' => 'Ø',
  37800. 'ù' => 'Ù',
  37801. 'ú' => 'Ú',
  37802. 'û' => 'Û',
  37803. 'ü' => 'Ü',
  37804. 'ý' => '�',
  37805. 'þ' => 'Þ',
  37806. 'ÿ' => 'Ÿ',
  37807. '�' => 'Ā',
  37808. 'ă' => 'Ă',
  37809. 'Ä…' => 'Ä„',
  37810. 'ć' => 'Ć',
  37811. 'ĉ' => 'Ĉ',
  37812. 'Ä‹' => 'ÄŠ',
  37813. '�' => 'Č',
  37814. '�' => 'Ď',
  37815. 'đ' => '�',
  37816. 'Ä“' => 'Ä’',
  37817. 'Ä•' => 'Ä”',
  37818. 'Ä—' => 'Ä–',
  37819. 'ę' => 'Ę',
  37820. 'Ä›' => 'Äš',
  37821. '�' => 'Ĝ',
  37822. 'ÄŸ' => 'Äž',
  37823. 'Ä¡' => 'Ä ',
  37824. 'Ä£' => 'Ä¢',
  37825. 'ĥ' => 'Ĥ',
  37826. 'ħ' => 'Ħ',
  37827. 'ĩ' => 'Ĩ',
  37828. 'ī' => 'Ī',
  37829. 'ĭ' => 'Ĭ',
  37830. 'į' => 'Į',
  37831. 'ı' => 'I',
  37832. 'ij' => 'IJ',
  37833. 'ĵ' => 'Ĵ',
  37834. 'ķ' => 'Ķ',
  37835. 'ĺ' => 'Ĺ',
  37836. 'ļ' => 'Ļ',
  37837. 'ľ' => 'Ľ',
  37838. 'Å€' => 'Ä¿',
  37839. 'ł' => '�',
  37840. 'ń' => 'Ń',
  37841. 'ņ' => 'Ņ',
  37842. 'ň' => 'Ň',
  37843. 'Å‹' => 'ÅŠ',
  37844. '�' => 'Ō',
  37845. '�' => 'Ŏ',
  37846. 'ő' => '�',
  37847. 'Å“' => 'Å’',
  37848. 'Å•' => 'Å”',
  37849. 'Å—' => 'Å–',
  37850. 'ř' => 'Ř',
  37851. 'Å›' => 'Åš',
  37852. '�' => 'Ŝ',
  37853. 'ÅŸ' => 'Åž',
  37854. 'Å¡' => 'Å ',
  37855. 'Å£' => 'Å¢',
  37856. 'ť' => 'Ť',
  37857. 'ŧ' => 'Ŧ',
  37858. 'ũ' => 'Ũ',
  37859. 'ū' => 'Ū',
  37860. 'ŭ' => 'Ŭ',
  37861. 'ů' => 'Ů',
  37862. 'ű' => 'Ű',
  37863. 'ų' => 'Ų',
  37864. 'ŵ' => 'Ŵ',
  37865. 'ŷ' => 'Ŷ',
  37866. 'ź' => 'Ź',
  37867. 'ż' => 'Ż',
  37868. 'ž' => 'Ž',
  37869. 'Å¿' => 'S',
  37870. 'ƀ' => 'Ƀ',
  37871. 'ƃ' => 'Ƃ',
  37872. 'Æ…' => 'Æ„',
  37873. 'ƈ' => 'Ƈ',
  37874. 'ƌ' => 'Ƌ',
  37875. 'Æ’' => 'Æ‘',
  37876. 'ƕ' => 'Ƕ',
  37877. 'ƙ' => 'Ƙ',
  37878. 'ƚ' => 'Ƚ',
  37879. 'Æž' => 'È ',
  37880. 'Æ¡' => 'Æ ',
  37881. 'Æ£' => 'Æ¢',
  37882. 'ƥ' => 'Ƥ',
  37883. 'ƨ' => 'Ƨ',
  37884. 'ƭ' => 'Ƭ',
  37885. 'ư' => 'Ư',
  37886. 'ƴ' => 'Ƴ',
  37887. 'ƶ' => 'Ƶ',
  37888. 'ƹ' => 'Ƹ',
  37889. 'ƽ' => 'Ƽ',
  37890. 'Æ¿' => 'Ç·',
  37891. 'Ç…' => 'Ç„',
  37892. 'dž' => 'DŽ',
  37893. 'Lj' => 'LJ',
  37894. 'lj' => 'LJ',
  37895. 'Ç‹' => 'ÇŠ',
  37896. 'nj' => 'NJ',
  37897. 'ǎ' => '�',
  37898. '�' => '�',
  37899. 'Ç’' => 'Ç‘',
  37900. 'Ç”' => 'Ç“',
  37901. 'Ç–' => 'Ç•',
  37902. 'ǘ' => 'Ǘ',
  37903. 'Çš' => 'Ç™',
  37904. 'ǜ' => 'Ǜ',
  37905. '�' => 'Ǝ',
  37906. 'ÇŸ' => 'Çž',
  37907. 'Ç¡' => 'Ç ',
  37908. 'Ç£' => 'Ç¢',
  37909. 'ǥ' => 'Ǥ',
  37910. 'ǧ' => 'Ǧ',
  37911. 'ǩ' => 'Ǩ',
  37912. 'ǫ' => 'Ǫ',
  37913. 'ǭ' => 'Ǭ',
  37914. 'ǯ' => 'Ǯ',
  37915. 'Dz' => 'DZ',
  37916. 'dz' => 'DZ',
  37917. 'ǵ' => 'Ǵ',
  37918. 'ǹ' => 'Ǹ',
  37919. 'ǻ' => 'Ǻ',
  37920. 'ǽ' => 'Ǽ',
  37921. 'ǿ' => 'Ǿ',
  37922. '�' => 'Ȁ',
  37923. 'ȃ' => 'Ȃ',
  37924. 'È…' => 'È„',
  37925. 'ȇ' => 'Ȇ',
  37926. 'ȉ' => 'Ȉ',
  37927. 'È‹' => 'ÈŠ',
  37928. '�' => 'Ȍ',
  37929. '�' => 'Ȏ',
  37930. 'ȑ' => '�',
  37931. 'È“' => 'È’',
  37932. 'È•' => 'È”',
  37933. 'È—' => 'È–',
  37934. 'ș' => 'Ș',
  37935. 'È›' => 'Èš',
  37936. '�' => 'Ȝ',
  37937. 'ÈŸ' => 'Èž',
  37938. 'È£' => 'È¢',
  37939. 'ȥ' => 'Ȥ',
  37940. 'ȧ' => 'Ȧ',
  37941. 'ȩ' => 'Ȩ',
  37942. 'ȫ' => 'Ȫ',
  37943. 'ȭ' => 'Ȭ',
  37944. 'ȯ' => 'Ȯ',
  37945. 'ȱ' => 'Ȱ',
  37946. 'ȳ' => 'Ȳ',
  37947. 'ȼ' => 'Ȼ',
  37948. 'È¿' => 'â±¾',
  37949. 'ɀ' => 'Ɀ',
  37950. 'ɂ' => '�',
  37951. 'ɇ' => 'Ɇ',
  37952. 'ɉ' => 'Ɉ',
  37953. 'É‹' => 'ÉŠ',
  37954. '�' => 'Ɍ',
  37955. '�' => 'Ɏ',
  37956. '�' => 'Ɐ',
  37957. 'É‘' => 'â±­',
  37958. 'É’' => 'â±°',
  37959. 'ɓ' => '�',
  37960. 'ɔ' => 'Ɔ',
  37961. 'ɖ' => 'Ɖ',
  37962. 'É—' => 'ÆŠ',
  37963. 'ə' => '�',
  37964. 'ɛ' => '�',
  37965. 'ɜ' => 'Ɜ',
  37966. 'É ' => 'Æ“',
  37967. 'ɡ' => 'Ɡ',
  37968. 'É£' => 'Æ”',
  37969. 'ɥ' => '�',
  37970. 'ɦ' => 'Ɦ',
  37971. 'ɨ' => 'Ɨ',
  37972. 'É©' => 'Æ–',
  37973. 'ɪ' => 'Ɪ',
  37974. 'É«' => 'â±¢',
  37975. 'ɬ' => 'Ɬ',
  37976. 'ɯ' => 'Ɯ',
  37977. 'ɱ' => 'Ɱ',
  37978. 'ɲ' => '�',
  37979. 'ɵ' => 'Ɵ',
  37980. 'ɽ' => 'Ɽ',
  37981. 'ʀ' => 'Ʀ',
  37982. 'ʂ' => 'Ʂ',
  37983. 'ʃ' => 'Ʃ',
  37984. 'ʇ' => 'Ʇ',
  37985. 'ʈ' => 'Ʈ',
  37986. 'ʉ' => 'Ʉ',
  37987. 'ʊ' => 'Ʊ',
  37988. 'ʋ' => 'Ʋ',
  37989. 'ʌ' => 'Ʌ',
  37990. 'Ê’' => 'Æ·',
  37991. '�' => 'Ʝ',
  37992. 'Êž' => 'êž°',
  37993. 'ͅ' => 'Ι',
  37994. 'ͱ' => 'Ͱ',
  37995. 'ͳ' => 'Ͳ',
  37996. 'ͷ' => 'Ͷ',
  37997. 'ͻ' => 'Ͻ',
  37998. 'ͼ' => 'Ͼ',
  37999. 'ͽ' => 'Ͽ',
  38000. 'ά' => 'Ά',
  38001. 'έ' => 'Έ',
  38002. 'ή' => 'Ή',
  38003. 'ί' => 'Ί',
  38004. 'α' => 'Α',
  38005. 'β' => 'Β',
  38006. 'γ' => 'Γ',
  38007. 'δ' => 'Δ',
  38008. 'ε' => 'Ε',
  38009. 'ζ' => 'Ζ',
  38010. 'η' => 'Η',
  38011. 'θ' => 'Θ',
  38012. 'ι' => 'Ι',
  38013. 'κ' => 'Κ',
  38014. 'λ' => 'Λ',
  38015. 'μ' => 'Μ',
  38016. 'ν' => '�',
  38017. 'ξ' => 'Ξ',
  38018. 'ο' => 'Ο',
  38019. 'π' => 'Π',
  38020. '�' => 'Ρ',
  38021. 'ς' => 'Σ',
  38022. 'σ' => 'Σ',
  38023. 'τ' => 'Τ',
  38024. 'Ï…' => 'Î¥',
  38025. 'φ' => 'Φ',
  38026. 'χ' => 'Χ',
  38027. 'ψ' => 'Ψ',
  38028. 'ω' => 'Ω',
  38029. 'ϊ' => 'Ϊ',
  38030. 'ϋ' => 'Ϋ',
  38031. 'ό' => 'Ό',
  38032. '�' => 'Ύ',
  38033. 'ώ' => '�',
  38034. '�' => 'Β',
  38035. 'ϑ' => 'Θ',
  38036. 'ϕ' => 'Φ',
  38037. 'ϖ' => 'Π',
  38038. 'ϗ' => '�',
  38039. 'ϙ' => 'Ϙ',
  38040. 'Ï›' => 'Ïš',
  38041. '�' => 'Ϝ',
  38042. 'ÏŸ' => 'Ïž',
  38043. 'Ï¡' => 'Ï ',
  38044. 'Ï£' => 'Ï¢',
  38045. 'ϥ' => 'Ϥ',
  38046. 'ϧ' => 'Ϧ',
  38047. 'ϩ' => 'Ϩ',
  38048. 'ϫ' => 'Ϫ',
  38049. 'ϭ' => 'Ϭ',
  38050. 'ϯ' => 'Ϯ',
  38051. 'ϰ' => 'Κ',
  38052. 'ϱ' => 'Ρ',
  38053. 'ϲ' => 'Ϲ',
  38054. 'ϳ' => 'Ϳ',
  38055. 'ϵ' => 'Ε',
  38056. 'ϸ' => 'Ϸ',
  38057. 'ϻ' => 'Ϻ',
  38058. 'а' => '�',
  38059. 'б' => 'Б',
  38060. 'в' => 'В',
  38061. 'г' => 'Г',
  38062. 'д' => 'Д',
  38063. 'е' => 'Е',
  38064. 'ж' => 'Ж',
  38065. 'з' => 'З',
  38066. 'и' => 'И',
  38067. 'й' => 'Й',
  38068. 'к' => 'К',
  38069. 'л' => 'Л',
  38070. 'м' => 'М',
  38071. 'н' => '�',
  38072. 'о' => 'О',
  38073. 'п' => 'П',
  38074. 'р' => 'Р',
  38075. '�' => 'С',
  38076. 'т' => 'Т',
  38077. 'у' => 'У',
  38078. 'ф' => 'Ф',
  38079. 'Ñ…' => 'Ð¥',
  38080. 'ц' => 'Ц',
  38081. 'ч' => 'Ч',
  38082. 'ш' => 'Ш',
  38083. 'щ' => 'Щ',
  38084. 'ъ' => 'Ъ',
  38085. 'ы' => 'Ы',
  38086. 'ь' => 'Ь',
  38087. '�' => 'Э',
  38088. 'ю' => 'Ю',
  38089. '�' => 'Я',
  38090. '�' => 'Ѐ',
  38091. 'ё' => '�',
  38092. 'ђ' => 'Ђ',
  38093. 'ѓ' => 'Ѓ',
  38094. 'є' => 'Є',
  38095. 'Ñ•' => 'Ð…',
  38096. 'і' => 'І',
  38097. 'ї' => 'Ї',
  38098. 'ј' => 'Ј',
  38099. 'љ' => 'Љ',
  38100. 'њ' => 'Њ',
  38101. 'ћ' => 'Ћ',
  38102. 'ќ' => 'Ќ',
  38103. '�' => '�',
  38104. 'Ñž' => 'ÐŽ',
  38105. 'џ' => '�',
  38106. 'Ñ¡' => 'Ñ ',
  38107. 'Ñ£' => 'Ñ¢',
  38108. 'ѥ' => 'Ѥ',
  38109. 'ѧ' => 'Ѧ',
  38110. 'ѩ' => 'Ѩ',
  38111. 'ѫ' => 'Ѫ',
  38112. 'ѭ' => 'Ѭ',
  38113. 'ѯ' => 'Ѯ',
  38114. 'ѱ' => 'Ѱ',
  38115. 'ѳ' => 'Ѳ',
  38116. 'ѵ' => 'Ѵ',
  38117. 'ѷ' => 'Ѷ',
  38118. 'ѹ' => 'Ѹ',
  38119. 'ѻ' => 'Ѻ',
  38120. 'ѽ' => 'Ѽ',
  38121. 'ѿ' => 'Ѿ',
  38122. 'Ò�' => 'Ò€',
  38123. 'Ò‹' => 'ÒŠ',
  38124. '�' => 'Ҍ',
  38125. 'Ò�' => 'ÒŽ',
  38126. 'Ò‘' => 'Ò�',
  38127. 'Ò“' => 'Ò’',
  38128. 'Ò•' => 'Ò”',
  38129. 'Ò—' => 'Ò–',
  38130. 'Ò™' => 'Ò˜',
  38131. 'Ò›' => 'Òš',
  38132. '�' => 'Ҝ',
  38133. 'ÒŸ' => 'Òž',
  38134. 'Ò¡' => 'Ò ',
  38135. 'Ò£' => 'Ò¢',
  38136. 'Ò¥' => 'Ò¤',
  38137. 'Ò§' => 'Ò¦',
  38138. 'Ò©' => 'Ò¨',
  38139. 'Ò«' => 'Òª',
  38140. 'Ò­' => 'Ò¬',
  38141. 'Ò¯' => 'Ò®',
  38142. 'Ò±' => 'Ò°',
  38143. 'Ò³' => 'Ò²',
  38144. 'Òµ' => 'Ò´',
  38145. 'Ò·' => 'Ò¶',
  38146. 'Ò¹' => 'Ò¸',
  38147. 'Ò»' => 'Òº',
  38148. 'Ò½' => 'Ò¼',
  38149. 'Ò¿' => 'Ò¾',
  38150. 'Ó‚' => 'Ó�',
  38151. 'Ó„' => 'Óƒ',
  38152. 'Ó†' => 'Ó…',
  38153. 'Óˆ' => 'Ó‡',
  38154. 'ÓŠ' => 'Ó‰',
  38155. 'ӌ' => 'Ӌ',
  38156. 'ÓŽ' => 'Ó�',
  38157. 'Ó�' => 'Ó€',
  38158. 'Ó‘' => 'Ó�',
  38159. 'Ó“' => 'Ó’',
  38160. 'Ó•' => 'Ó”',
  38161. 'Ó—' => 'Ó–',
  38162. 'Ó™' => 'Ó˜',
  38163. 'Ó›' => 'Óš',
  38164. '�' => 'Ӝ',
  38165. 'ÓŸ' => 'Óž',
  38166. 'Ó¡' => 'Ó ',
  38167. 'Ó£' => 'Ó¢',
  38168. 'Ó¥' => 'Ó¤',
  38169. 'Ó§' => 'Ó¦',
  38170. 'Ó©' => 'Ó¨',
  38171. 'Ó«' => 'Óª',
  38172. 'Ó­' => 'Ó¬',
  38173. 'Ó¯' => 'Ó®',
  38174. 'Ó±' => 'Ó°',
  38175. 'Ó³' => 'Ó²',
  38176. 'Óµ' => 'Ó´',
  38177. 'Ó·' => 'Ó¶',
  38178. 'Ó¹' => 'Ó¸',
  38179. 'Ó»' => 'Óº',
  38180. 'Ó½' => 'Ó¼',
  38181. 'Ó¿' => 'Ó¾',
  38182. 'Ô�' => 'Ô€',
  38183. 'Ôƒ' => 'Ô‚',
  38184. 'Ô…' => 'Ô„',
  38185. 'Ô‡' => 'Ô†',
  38186. 'Ô‰' => 'Ôˆ',
  38187. 'Ô‹' => 'ÔŠ',
  38188. '�' => 'Ԍ',
  38189. 'Ô�' => 'ÔŽ',
  38190. 'Ô‘' => 'Ô�',
  38191. 'Ô“' => 'Ô’',
  38192. 'Ô•' => 'Ô”',
  38193. 'Ô—' => 'Ô–',
  38194. 'Ô™' => 'Ô˜',
  38195. 'Ô›' => 'Ôš',
  38196. '�' => 'Ԝ',
  38197. 'ÔŸ' => 'Ôž',
  38198. 'Ô¡' => 'Ô ',
  38199. 'Ô£' => 'Ô¢',
  38200. 'Ô¥' => 'Ô¤',
  38201. 'Ô§' => 'Ô¦',
  38202. 'Ô©' => 'Ô¨',
  38203. 'Ô«' => 'Ôª',
  38204. 'Ô­' => 'Ô¬',
  38205. 'Ô¯' => 'Ô®',
  38206. 'Õ¡' => 'Ô±',
  38207. 'Õ¢' => 'Ô²',
  38208. 'Õ£' => 'Ô³',
  38209. 'Õ¤' => 'Ô´',
  38210. 'Õ¥' => 'Ôµ',
  38211. 'Õ¦' => 'Ô¶',
  38212. 'Õ§' => 'Ô·',
  38213. 'Õ¨' => 'Ô¸',
  38214. 'Õ©' => 'Ô¹',
  38215. 'Õª' => 'Ôº',
  38216. 'Õ«' => 'Ô»',
  38217. 'Õ¬' => 'Ô¼',
  38218. 'Õ­' => 'Ô½',
  38219. 'Õ®' => 'Ô¾',
  38220. 'Õ¯' => 'Ô¿',
  38221. 'Õ°' => 'Õ€',
  38222. 'Õ±' => 'Õ�',
  38223. 'Õ²' => 'Õ‚',
  38224. 'Õ³' => 'Õƒ',
  38225. 'Õ´' => 'Õ„',
  38226. 'Õµ' => 'Õ…',
  38227. 'Õ¶' => 'Õ†',
  38228. 'Õ·' => 'Õ‡',
  38229. 'Õ¸' => 'Õˆ',
  38230. 'Õ¹' => 'Õ‰',
  38231. 'Õº' => 'ÕŠ',
  38232. 'Õ»' => 'Õ‹',
  38233. 'ռ' => 'Ռ',
  38234. 'Õ½' => 'Õ�',
  38235. 'Õ¾' => 'ÕŽ',
  38236. 'Õ¿' => 'Õ�',
  38237. 'Ö€' => 'Õ�',
  38238. 'Ö�' => 'Õ‘',
  38239. 'Ö‚' => 'Õ’',
  38240. 'Öƒ' => 'Õ“',
  38241. 'Ö„' => 'Õ”',
  38242. 'Ö…' => 'Õ•',
  38243. 'Ö†' => 'Õ–',
  38244. '�' => '�',
  38245. 'ბ' => 'Ბ',
  38246. 'გ' => 'Გ',
  38247. 'დ' => 'Დ',
  38248. 'ე' => 'Ე',
  38249. 'ვ' => 'Ვ',
  38250. 'ზ' => 'Ზ',
  38251. 'თ' => 'Თ',
  38252. 'ი' => 'Ი',
  38253. 'კ' => 'Კ',
  38254. 'ლ' => 'Ლ',
  38255. 'მ' => 'Მ',
  38256. 'ნ' => 'Ნ',
  38257. '�' => '�',
  38258. 'პ' => 'Პ',
  38259. 'ჟ' => 'Ჟ',
  38260. 'რ' => 'Რ',
  38261. 'ს' => 'Ს',
  38262. 'ტ' => 'Ტ',
  38263. 'უ' => 'Უ',
  38264. 'ფ' => 'Ფ',
  38265. 'ქ' => 'Ქ',
  38266. 'ღ' => 'Ღ',
  38267. 'ყ' => 'Ყ',
  38268. 'შ' => 'Შ',
  38269. 'ჩ' => 'Ჩ',
  38270. 'ც' => 'Ც',
  38271. 'ძ' => 'Ძ',
  38272. 'წ' => 'Წ',
  38273. 'ჭ' => 'Ჭ',
  38274. 'ხ' => 'Ხ',
  38275. 'ჯ' => 'Ჯ',
  38276. 'ჰ' => 'Ჰ',
  38277. 'ჱ' => 'Ჱ',
  38278. 'ჲ' => 'Ჲ',
  38279. 'ჳ' => 'Ჳ',
  38280. 'ჴ' => 'Ჴ',
  38281. 'ჵ' => 'Ჵ',
  38282. 'ჶ' => 'Ჶ',
  38283. 'ჷ' => 'Ჷ',
  38284. 'ჸ' => 'Ჸ',
  38285. 'ჹ' => 'Ჹ',
  38286. 'ჺ' => 'Ჺ',
  38287. 'ჽ' => 'Ჽ',
  38288. 'ჾ' => 'Ჾ',
  38289. 'ჿ' => 'Ჿ',
  38290. '�' => '�',
  38291. '�' => '�',
  38292. '�' => '�',
  38293. '�' => '�',
  38294. '�' => '�',
  38295. '�' => '�',
  38296. 'á²€' => 'Ð’',
  38297. '�' => 'Д',
  38298. 'ᲂ' => 'О',
  38299. 'ᲃ' => 'С',
  38300. 'ᲄ' => 'Т',
  38301. 'ᲅ' => 'Т',
  38302. 'ᲆ' => 'Ъ',
  38303. 'ᲇ' => 'Ѣ',
  38304. 'ᲈ' => 'Ꙋ',
  38305. 'ᵹ' => '�',
  38306. 'áµ½' => 'â±£',
  38307. 'ᶎ' => 'Ᶎ',
  38308. '�' => 'Ḁ',
  38309. 'ḃ' => 'Ḃ',
  38310. 'ḅ' => 'Ḅ',
  38311. 'ḇ' => 'Ḇ',
  38312. 'ḉ' => 'Ḉ',
  38313. 'ḋ' => 'Ḋ',
  38314. '�' => 'Ḍ',
  38315. '�' => 'Ḏ',
  38316. 'ḑ' => '�',
  38317. 'ḓ' => 'Ḓ',
  38318. 'ḕ' => 'Ḕ',
  38319. 'ḗ' => 'Ḗ',
  38320. 'ḙ' => 'Ḙ',
  38321. 'ḛ' => 'Ḛ',
  38322. '�' => 'Ḝ',
  38323. 'ḟ' => 'Ḟ',
  38324. 'ḡ' => 'Ḡ',
  38325. 'ḣ' => 'Ḣ',
  38326. 'ḥ' => 'Ḥ',
  38327. 'ḧ' => 'Ḧ',
  38328. 'ḩ' => 'Ḩ',
  38329. 'ḫ' => 'Ḫ',
  38330. 'ḭ' => 'Ḭ',
  38331. 'ḯ' => 'Ḯ',
  38332. 'ḱ' => 'Ḱ',
  38333. 'ḳ' => 'Ḳ',
  38334. 'ḵ' => 'Ḵ',
  38335. 'ḷ' => 'Ḷ',
  38336. 'ḹ' => 'Ḹ',
  38337. 'ḻ' => 'Ḻ',
  38338. 'ḽ' => 'Ḽ',
  38339. 'ḿ' => 'Ḿ',
  38340. '�' => 'Ṁ',
  38341. 'ṃ' => 'Ṃ',
  38342. 'ṅ' => 'Ṅ',
  38343. 'ṇ' => 'Ṇ',
  38344. 'ṉ' => 'Ṉ',
  38345. 'ṋ' => 'Ṋ',
  38346. '�' => 'Ṍ',
  38347. '�' => 'Ṏ',
  38348. 'ṑ' => '�',
  38349. 'ṓ' => 'Ṓ',
  38350. 'ṕ' => 'Ṕ',
  38351. 'á¹—' => 'á¹–',
  38352. 'ṙ' => 'Ṙ',
  38353. 'ṛ' => 'Ṛ',
  38354. '�' => 'Ṝ',
  38355. 'ṟ' => 'Ṟ',
  38356. 'ṡ' => 'Ṡ',
  38357. 'á¹£' => 'á¹¢',
  38358. 'ṥ' => 'Ṥ',
  38359. 'ṧ' => 'Ṧ',
  38360. 'ṩ' => 'Ṩ',
  38361. 'ṫ' => 'Ṫ',
  38362. 'ṭ' => 'Ṭ',
  38363. 'ṯ' => 'Ṯ',
  38364. 'á¹±' => 'á¹°',
  38365. 'á¹³' => 'á¹²',
  38366. 'á¹µ' => 'á¹´',
  38367. 'á¹·' => 'á¹¶',
  38368. 'ṹ' => 'Ṹ',
  38369. 'ṻ' => 'Ṻ',
  38370. 'á¹½' => 'á¹¼',
  38371. 'ṿ' => 'Ṿ',
  38372. '�' => 'Ẁ',
  38373. 'ẃ' => 'Ẃ',
  38374. 'ẅ' => 'Ẅ',
  38375. 'ẇ' => 'Ẇ',
  38376. 'ẉ' => 'Ẉ',
  38377. 'ẋ' => 'Ẋ',
  38378. '�' => 'Ẍ',
  38379. '�' => 'Ẏ',
  38380. 'ẑ' => '�',
  38381. 'ẓ' => 'Ẓ',
  38382. 'ẕ' => 'Ẕ',
  38383. 'ẛ' => 'Ṡ',
  38384. 'ạ' => 'Ạ',
  38385. 'ả' => 'Ả',
  38386. 'ấ' => 'Ấ',
  38387. 'ầ' => 'Ầ',
  38388. 'ẩ' => 'Ẩ',
  38389. 'ẫ' => 'Ẫ',
  38390. 'ậ' => 'Ậ',
  38391. 'ắ' => 'Ắ',
  38392. 'ằ' => 'Ằ',
  38393. 'ẳ' => 'Ẳ',
  38394. 'ẵ' => 'Ẵ',
  38395. 'ặ' => 'Ặ',
  38396. 'ẹ' => 'Ẹ',
  38397. 'ẻ' => 'Ẻ',
  38398. 'ẽ' => 'Ẽ',
  38399. 'ế' => 'Ế',
  38400. '�' => 'Ề',
  38401. 'ể' => 'Ể',
  38402. 'ễ' => 'Ễ',
  38403. 'ệ' => 'Ệ',
  38404. 'ỉ' => 'Ỉ',
  38405. 'ị' => 'Ị',
  38406. '�' => 'Ọ',
  38407. '�' => 'Ỏ',
  38408. 'ố' => '�',
  38409. 'ồ' => 'Ồ',
  38410. 'ổ' => 'Ổ',
  38411. 'á»—' => 'á»–',
  38412. 'ộ' => 'Ộ',
  38413. 'ớ' => 'Ớ',
  38414. '�' => 'Ờ',
  38415. 'ở' => 'Ở',
  38416. 'ỡ' => 'Ỡ',
  38417. 'ợ' => 'Ợ',
  38418. 'ụ' => 'Ụ',
  38419. 'ủ' => 'Ủ',
  38420. 'ứ' => 'Ứ',
  38421. 'ừ' => 'Ừ',
  38422. 'ử' => 'Ử',
  38423. 'ữ' => 'Ữ',
  38424. 'á»±' => 'á»°',
  38425. 'ỳ' => 'Ỳ',
  38426. 'ỵ' => 'Ỵ',
  38427. 'á»·' => 'á»¶',
  38428. 'ỹ' => 'Ỹ',
  38429. 'ỻ' => 'Ỻ',
  38430. 'ỽ' => 'Ỽ',
  38431. 'ỿ' => 'Ỿ',
  38432. 'ἀ' => 'Ἀ',
  38433. '�' => 'Ἁ',
  38434. 'ἂ' => 'Ἂ',
  38435. 'ἃ' => 'Ἃ',
  38436. 'ἄ' => 'Ἄ',
  38437. 'ἅ' => '�',
  38438. 'ἆ' => 'Ἆ',
  38439. 'ἇ' => '�',
  38440. '�' => 'Ἐ',
  38441. 'ἑ' => 'Ἑ',
  38442. 'ἒ' => 'Ἒ',
  38443. 'ἓ' => 'Ἓ',
  38444. 'ἔ' => 'Ἔ',
  38445. 'ἕ' => '�',
  38446. 'ἠ' => 'Ἠ',
  38447. 'ἡ' => 'Ἡ',
  38448. 'ἢ' => 'Ἢ',
  38449. 'ἣ' => 'Ἣ',
  38450. 'ἤ' => 'Ἤ',
  38451. 'á¼¥' => 'á¼­',
  38452. 'ἦ' => 'Ἦ',
  38453. 'ἧ' => 'Ἧ',
  38454. 'ἰ' => 'Ἰ',
  38455. 'á¼±' => 'á¼¹',
  38456. 'ἲ' => 'Ἲ',
  38457. 'á¼³' => 'á¼»',
  38458. 'á¼´' => 'á¼¼',
  38459. 'á¼µ' => 'á¼½',
  38460. 'á¼¶' => 'á¼¾',
  38461. 'ἷ' => 'Ἷ',
  38462. 'ὀ' => 'Ὀ',
  38463. '�' => 'Ὁ',
  38464. 'ὂ' => 'Ὂ',
  38465. 'ὃ' => 'Ὃ',
  38466. 'ὄ' => 'Ὄ',
  38467. 'ὅ' => '�',
  38468. 'ὑ' => 'Ὑ',
  38469. 'ὓ' => 'Ὓ',
  38470. 'ὕ' => '�',
  38471. 'ὗ' => 'Ὗ',
  38472. 'ὠ' => 'Ὠ',
  38473. 'ὡ' => 'Ὡ',
  38474. 'ὢ' => 'Ὢ',
  38475. 'ὣ' => 'Ὣ',
  38476. 'ὤ' => 'Ὤ',
  38477. 'á½¥' => 'á½­',
  38478. 'ὦ' => 'Ὦ',
  38479. 'ὧ' => 'Ὧ',
  38480. 'ὰ' => 'Ὰ',
  38481. 'á½±' => 'á¾»',
  38482. 'ὲ' => 'Ὲ',
  38483. 'έ' => 'Έ',
  38484. 'ὴ' => 'Ὴ',
  38485. 'á½µ' => 'á¿‹',
  38486. 'ὶ' => 'Ὶ',
  38487. 'á½·' => 'á¿›',
  38488. 'ὸ' => 'Ὸ',
  38489. 'ό' => 'Ό',
  38490. 'ὺ' => 'Ὺ',
  38491. 'á½»' => 'á¿«',
  38492. 'ὼ' => 'Ὼ',
  38493. 'á½½' => 'á¿»',
  38494. 'ᾀ' => 'ἈΙ',
  38495. '�' => 'ἉΙ',
  38496. 'ᾂ' => 'ἊΙ',
  38497. 'ᾃ' => 'ἋΙ',
  38498. 'ᾄ' => 'ἌΙ',
  38499. 'ᾅ' => '�Ι',
  38500. 'ᾆ' => 'ἎΙ',
  38501. 'ᾇ' => '�Ι',
  38502. '�' => 'ἨΙ',
  38503. 'ᾑ' => 'ἩΙ',
  38504. 'ᾒ' => 'ἪΙ',
  38505. 'ᾓ' => 'ἫΙ',
  38506. 'ᾔ' => 'ἬΙ',
  38507. 'ᾕ' => 'ἭΙ',
  38508. 'ᾖ' => 'ἮΙ',
  38509. 'ᾗ' => 'ἯΙ',
  38510. 'ᾠ' => 'ὨΙ',
  38511. 'ᾡ' => 'ὩΙ',
  38512. 'ᾢ' => 'ὪΙ',
  38513. 'ᾣ' => 'ὫΙ',
  38514. 'ᾤ' => 'ὬΙ',
  38515. 'ᾥ' => 'ὭΙ',
  38516. 'ᾦ' => 'ὮΙ',
  38517. 'ᾧ' => 'ὯΙ',
  38518. 'ᾰ' => 'Ᾰ',
  38519. 'á¾±' => 'á¾¹',
  38520. 'ᾳ' => 'ΑΙ',
  38521. 'ι' => 'Ι',
  38522. 'ῃ' => 'ΗΙ',
  38523. '�' => 'Ῐ',
  38524. 'á¿‘' => 'á¿™',
  38525. 'ῠ' => 'Ῠ',
  38526. 'á¿¡' => 'á¿©',
  38527. 'ῥ' => 'Ῥ',
  38528. 'ῳ' => 'ΩΙ',
  38529. 'ⅎ' => 'Ⅎ',
  38530. 'â…°' => 'â… ',
  38531. 'â…±' => 'â…¡',
  38532. 'â…²' => 'â…¢',
  38533. 'â…³' => 'â…£',
  38534. 'â…´' => 'â…¤',
  38535. 'â…µ' => 'â…¥',
  38536. 'â…¶' => 'â…¦',
  38537. 'â…·' => 'â…§',
  38538. 'â…¸' => 'â…¨',
  38539. 'â…¹' => 'â…©',
  38540. 'â…º' => 'â…ª',
  38541. 'â…»' => 'â…«',
  38542. 'â…¼' => 'â…¬',
  38543. 'â…½' => 'â…­',
  38544. 'â…¾' => 'â…®',
  38545. 'â…¿' => 'â…¯',
  38546. 'ↄ' => 'Ↄ',
  38547. '�' => 'Ⓐ',
  38548. 'â“‘' => 'â’·',
  38549. 'â“’' => 'â’¸',
  38550. 'â““' => 'â’¹',
  38551. 'â“”' => 'â’º',
  38552. 'â“•' => 'â’»',
  38553. 'â“–' => 'â’¼',
  38554. 'â“—' => 'â’½',
  38555. 'ⓘ' => 'Ⓘ',
  38556. 'â“™' => 'â’¿',
  38557. 'ⓚ' => 'Ⓚ',
  38558. 'ⓛ' => '�',
  38559. 'ⓜ' => 'Ⓜ',
  38560. '�' => 'Ⓝ',
  38561. 'ⓞ' => 'Ⓞ',
  38562. 'ⓟ' => 'Ⓟ',
  38563. 'ⓠ' => 'Ⓠ',
  38564. 'ⓡ' => 'Ⓡ',
  38565. 'ⓢ' => 'Ⓢ',
  38566. 'ⓣ' => 'Ⓣ',
  38567. 'ⓤ' => 'Ⓤ',
  38568. 'â“¥' => 'â“‹',
  38569. 'ⓦ' => 'Ⓦ',
  38570. 'ⓧ' => '�',
  38571. 'ⓨ' => 'Ⓨ',
  38572. 'ⓩ' => '�',
  38573. 'â°°' => 'â°€',
  38574. 'â°±' => 'â°�',
  38575. 'â°²' => 'â°‚',
  38576. 'â°³' => 'â°ƒ',
  38577. 'â°´' => 'â°„',
  38578. 'â°µ' => 'â°…',
  38579. 'â°¶' => 'â°†',
  38580. 'â°·' => 'â°‡',
  38581. 'â°¸' => 'â°ˆ',
  38582. 'â°¹' => 'â°‰',
  38583. 'â°º' => 'â°Š',
  38584. 'â°»' => 'â°‹',
  38585. 'ⰼ' => 'Ⰼ',
  38586. 'â°½' => 'â°�',
  38587. 'â°¾' => 'â°Ž',
  38588. 'â°¿' => 'â°�',
  38589. 'â±€' => 'â°�',
  38590. '�' => 'Ⱁ',
  38591. 'ⱂ' => 'Ⱂ',
  38592. 'ⱃ' => 'Ⱃ',
  38593. 'ⱄ' => 'Ⱄ',
  38594. 'â±…' => 'â°•',
  38595. 'ⱆ' => 'Ⱆ',
  38596. 'ⱇ' => 'Ⱇ',
  38597. 'ⱈ' => 'Ⱈ',
  38598. 'ⱉ' => 'Ⱉ',
  38599. 'ⱊ' => 'Ⱊ',
  38600. 'ⱋ' => 'Ⱋ',
  38601. 'ⱌ' => 'Ⱌ',
  38602. '�' => '�',
  38603. 'ⱎ' => 'Ⱎ',
  38604. '�' => 'Ⱏ',
  38605. '�' => 'Ⱐ',
  38606. 'ⱑ' => 'Ⱑ',
  38607. 'â±’' => 'â°¢',
  38608. 'ⱓ' => 'Ⱓ',
  38609. 'â±”' => 'â°¤',
  38610. 'ⱕ' => 'Ⱕ',
  38611. 'â±–' => 'â°¦',
  38612. 'â±—' => 'â°§',
  38613. 'ⱘ' => 'Ⱘ',
  38614. 'â±™' => 'â°©',
  38615. 'ⱚ' => 'Ⱚ',
  38616. 'â±›' => 'â°«',
  38617. 'ⱜ' => 'Ⱜ',
  38618. '�' => 'Ⱝ',
  38619. 'ⱞ' => 'Ⱞ',
  38620. 'ⱡ' => 'Ⱡ',
  38621. 'ⱥ' => 'Ⱥ',
  38622. 'ⱦ' => 'Ⱦ',
  38623. 'ⱨ' => 'Ⱨ',
  38624. 'ⱪ' => 'Ⱪ',
  38625. 'ⱬ' => 'Ⱬ',
  38626. 'â±³' => 'â±²',
  38627. 'â±¶' => 'â±µ',
  38628. '�' => 'Ⲁ',
  38629. 'ⲃ' => 'Ⲃ',
  38630. 'ⲅ' => 'Ⲅ',
  38631. 'ⲇ' => 'Ⲇ',
  38632. 'ⲉ' => 'Ⲉ',
  38633. 'ⲋ' => 'Ⲋ',
  38634. '�' => 'Ⲍ',
  38635. '�' => 'Ⲏ',
  38636. 'ⲑ' => '�',
  38637. 'ⲓ' => 'Ⲓ',
  38638. 'ⲕ' => 'Ⲕ',
  38639. 'â²—' => 'â²–',
  38640. 'ⲙ' => 'Ⲙ',
  38641. 'ⲛ' => 'Ⲛ',
  38642. '�' => 'Ⲝ',
  38643. 'ⲟ' => 'Ⲟ',
  38644. 'ⲡ' => 'Ⲡ',
  38645. 'â²£' => 'â²¢',
  38646. 'ⲥ' => 'Ⲥ',
  38647. 'ⲧ' => 'Ⲧ',
  38648. 'ⲩ' => 'Ⲩ',
  38649. 'ⲫ' => 'Ⲫ',
  38650. 'ⲭ' => 'Ⲭ',
  38651. 'ⲯ' => 'Ⲯ',
  38652. 'â²±' => 'â²°',
  38653. 'â²³' => 'â²²',
  38654. 'â²µ' => 'â²´',
  38655. 'â²·' => 'â²¶',
  38656. 'ⲹ' => 'Ⲹ',
  38657. 'ⲻ' => 'Ⲻ',
  38658. 'â²½' => 'â²¼',
  38659. 'ⲿ' => 'Ⲿ',
  38660. '�' => 'Ⳁ',
  38661. 'ⳃ' => 'Ⳃ',
  38662. 'ⳅ' => 'Ⳅ',
  38663. 'ⳇ' => 'Ⳇ',
  38664. 'ⳉ' => 'Ⳉ',
  38665. 'ⳋ' => 'Ⳋ',
  38666. '�' => 'Ⳍ',
  38667. '�' => 'Ⳏ',
  38668. 'ⳑ' => '�',
  38669. 'ⳓ' => 'Ⳓ',
  38670. 'ⳕ' => 'Ⳕ',
  38671. 'â³—' => 'â³–',
  38672. 'ⳙ' => 'Ⳙ',
  38673. 'ⳛ' => 'Ⳛ',
  38674. '�' => 'Ⳝ',
  38675. 'ⳟ' => 'Ⳟ',
  38676. 'ⳡ' => 'Ⳡ',
  38677. 'â³£' => 'â³¢',
  38678. 'ⳬ' => 'Ⳬ',
  38679. 'â³®' => 'â³­',
  38680. 'â³³' => 'â³²',
  38681. 'â´€' => 'á‚ ',
  38682. 'â´�' => 'á‚¡',
  38683. 'â´‚' => 'á‚¢',
  38684. 'â´ƒ' => 'á‚£',
  38685. 'ⴄ' => 'Ⴄ',
  38686. 'â´…' => 'á‚¥',
  38687. 'ⴆ' => 'Ⴆ',
  38688. 'â´‡' => 'á‚§',
  38689. 'ⴈ' => 'Ⴈ',
  38690. 'â´‰' => 'á‚©',
  38691. 'ⴊ' => 'Ⴊ',
  38692. 'â´‹' => 'á‚«',
  38693. 'ⴌ' => 'Ⴌ',
  38694. 'â´�' => 'á‚­',
  38695. 'â´Ž' => 'á‚®',
  38696. '�' => 'Ⴏ',
  38697. 'â´�' => 'á‚°',
  38698. 'ⴑ' => 'Ⴑ',
  38699. 'ⴒ' => 'Ⴒ',
  38700. 'ⴓ' => 'Ⴓ',
  38701. 'â´”' => 'á‚´',
  38702. 'ⴕ' => 'Ⴕ',
  38703. 'â´–' => 'á‚¶',
  38704. 'â´—' => 'á‚·',
  38705. 'ⴘ' => 'Ⴘ',
  38706. 'ⴙ' => 'Ⴙ',
  38707. 'ⴚ' => 'Ⴚ',
  38708. 'â´›' => 'á‚»',
  38709. 'ⴜ' => 'Ⴜ',
  38710. '�' => 'Ⴝ',
  38711. 'ⴞ' => 'Ⴞ',
  38712. 'â´Ÿ' => 'á‚¿',
  38713. 'ⴠ' => 'Ⴠ',
  38714. 'ⴡ' => '�',
  38715. 'ⴢ' => 'Ⴢ',
  38716. 'ⴣ' => 'Ⴣ',
  38717. 'ⴤ' => 'Ⴤ',
  38718. 'ⴥ' => 'Ⴥ',
  38719. 'ⴧ' => 'Ⴧ',
  38720. 'ⴭ' => '�',
  38721. '�' => 'Ꙁ',
  38722. 'ꙃ' => 'Ꙃ',
  38723. 'ꙅ' => 'Ꙅ',
  38724. 'ꙇ' => 'Ꙇ',
  38725. 'ꙉ' => 'Ꙉ',
  38726. 'ꙋ' => 'Ꙋ',
  38727. '�' => 'Ꙍ',
  38728. '�' => 'Ꙏ',
  38729. 'ꙑ' => '�',
  38730. 'ꙓ' => 'Ꙓ',
  38731. 'ꙕ' => 'Ꙕ',
  38732. 'ê™—' => 'ê™–',
  38733. 'ꙙ' => 'Ꙙ',
  38734. 'ꙛ' => 'Ꙛ',
  38735. '�' => 'Ꙝ',
  38736. 'ꙟ' => 'Ꙟ',
  38737. 'ꙡ' => 'Ꙡ',
  38738. 'ꙣ' => 'Ꙣ',
  38739. 'ꙥ' => 'Ꙥ',
  38740. 'ꙧ' => 'Ꙧ',
  38741. 'ꙩ' => 'Ꙩ',
  38742. 'ꙫ' => 'Ꙫ',
  38743. 'ꙭ' => 'Ꙭ',
  38744. '�' => 'Ꚁ',
  38745. 'ꚃ' => 'Ꚃ',
  38746. 'êš…' => 'êš„',
  38747. 'ꚇ' => 'Ꚇ',
  38748. 'ꚉ' => 'Ꚉ',
  38749. 'ꚋ' => 'Ꚋ',
  38750. '�' => 'Ꚍ',
  38751. '�' => 'Ꚏ',
  38752. 'ꚑ' => '�',
  38753. 'êš“' => 'êš’',
  38754. 'êš•' => 'êš”',
  38755. 'êš—' => 'êš–',
  38756. 'ꚙ' => 'Ꚙ',
  38757. 'êš›' => 'êšš',
  38758. 'ꜣ' => 'Ꜣ',
  38759. 'ꜥ' => 'Ꜥ',
  38760. 'ꜧ' => 'Ꜧ',
  38761. 'ꜩ' => 'Ꜩ',
  38762. 'ꜫ' => 'Ꜫ',
  38763. 'ꜭ' => 'Ꜭ',
  38764. 'ꜯ' => 'Ꜯ',
  38765. 'ꜳ' => 'Ꜳ',
  38766. 'ꜵ' => 'Ꜵ',
  38767. 'ꜷ' => 'Ꜷ',
  38768. 'ꜹ' => 'Ꜹ',
  38769. 'ꜻ' => 'Ꜻ',
  38770. 'ꜽ' => 'Ꜽ',
  38771. 'ꜿ' => 'Ꜿ',
  38772. '�' => '�',
  38773. '�' => '�',
  38774. '�' => '�',
  38775. '�' => '�',
  38776. '�' => '�',
  38777. '�' => '�',
  38778. '�' => '�',
  38779. '�' => '�',
  38780. '�' => '�',
  38781. '�' => '�',
  38782. '�' => '�',
  38783. '�' => '�',
  38784. '�' => '�',
  38785. '�' => '�',
  38786. '�' => '�',
  38787. '�' => '�',
  38788. '�' => '�',
  38789. '�' => '�',
  38790. '�' => '�',
  38791. '�' => '�',
  38792. '�' => '�',
  38793. '�' => '�',
  38794. '�' => '�',
  38795. '�' => '�',
  38796. '�' => '�',
  38797. '�' => '�',
  38798. '�' => '�',
  38799. '�' => 'Ꞁ',
  38800. 'ꞃ' => 'Ꞃ',
  38801. 'êž…' => 'êž„',
  38802. 'ꞇ' => 'Ꞇ',
  38803. 'ꞌ' => 'Ꞌ',
  38804. 'ꞑ' => '�',
  38805. 'êž“' => 'êž’',
  38806. 'ꞔ' => 'Ꞔ',
  38807. 'êž—' => 'êž–',
  38808. 'ꞙ' => 'Ꞙ',
  38809. 'êž›' => 'êžš',
  38810. '�' => 'Ꞝ',
  38811. 'ꞟ' => 'Ꞟ',
  38812. 'êž¡' => 'êž ',
  38813. 'ꞣ' => 'Ꞣ',
  38814. 'ꞥ' => 'Ꞥ',
  38815. 'ꞧ' => 'Ꞧ',
  38816. 'ꞩ' => 'Ꞩ',
  38817. 'êžµ' => 'êž´',
  38818. 'êž·' => 'êž¶',
  38819. 'ꞹ' => 'Ꞹ',
  38820. 'ꞻ' => 'Ꞻ',
  38821. 'êž½' => 'êž¼',
  38822. 'êž¿' => 'êž¾',
  38823. 'ꟃ' => 'Ꟃ',
  38824. 'ꟈ' => 'Ꟈ',
  38825. 'ꟊ' => 'Ꟊ',
  38826. 'ꟶ' => 'Ꟶ',
  38827. 'ê­“' => 'êž³',
  38828. 'ꭰ' => 'Ꭰ',
  38829. 'ꭱ' => 'Ꭱ',
  38830. 'ꭲ' => 'Ꭲ',
  38831. 'ꭳ' => 'Ꭳ',
  38832. 'ꭴ' => 'Ꭴ',
  38833. 'ꭵ' => 'Ꭵ',
  38834. 'ꭶ' => 'Ꭶ',
  38835. 'ꭷ' => 'Ꭷ',
  38836. 'ꭸ' => 'Ꭸ',
  38837. 'ꭹ' => 'Ꭹ',
  38838. 'ꭺ' => 'Ꭺ',
  38839. 'ꭻ' => 'Ꭻ',
  38840. 'ꭼ' => 'Ꭼ',
  38841. 'ꭽ' => 'Ꭽ',
  38842. 'ꭾ' => 'Ꭾ',
  38843. 'ꭿ' => 'Ꭿ',
  38844. 'ꮀ' => 'Ꮀ',
  38845. '�' => 'Ꮁ',
  38846. 'ꮂ' => 'Ꮂ',
  38847. 'ꮃ' => 'Ꮃ',
  38848. 'ꮄ' => 'Ꮄ',
  38849. 'ꮅ' => 'Ꮅ',
  38850. 'ꮆ' => 'Ꮆ',
  38851. 'ꮇ' => 'Ꮇ',
  38852. 'ꮈ' => 'Ꮈ',
  38853. 'ꮉ' => 'Ꮉ',
  38854. 'ꮊ' => 'Ꮊ',
  38855. 'ꮋ' => 'Ꮋ',
  38856. 'ꮌ' => 'Ꮌ',
  38857. '�' => 'Ꮍ',
  38858. 'ꮎ' => 'Ꮎ',
  38859. '�' => 'Ꮏ',
  38860. '�' => '�',
  38861. 'ꮑ' => '�',
  38862. 'ꮒ' => '�',
  38863. 'ꮓ' => '�',
  38864. 'ꮔ' => '�',
  38865. 'ꮕ' => '�',
  38866. 'ꮖ' => '�',
  38867. 'ꮗ' => '�',
  38868. 'ꮘ' => '�',
  38869. 'ꮙ' => '�',
  38870. 'ꮚ' => '�',
  38871. 'ꮛ' => '�',
  38872. 'ꮜ' => '�',
  38873. '�' => '�',
  38874. 'ꮞ' => '�',
  38875. 'ꮟ' => '�',
  38876. 'ꮠ' => '�',
  38877. 'ꮡ' => '�',
  38878. 'ꮢ' => '�',
  38879. 'ꮣ' => '�',
  38880. 'ꮤ' => '�',
  38881. 'ꮥ' => '�',
  38882. 'ꮦ' => '�',
  38883. 'ꮧ' => '�',
  38884. 'ꮨ' => '�',
  38885. 'ꮩ' => '�',
  38886. 'ꮪ' => '�',
  38887. 'ꮫ' => '�',
  38888. 'ꮬ' => '�',
  38889. 'ꮭ' => '�',
  38890. 'ꮮ' => '�',
  38891. 'ꮯ' => '�',
  38892. 'ꮰ' => '�',
  38893. 'ꮱ' => '�',
  38894. 'ꮲ' => '�',
  38895. 'ꮳ' => '�',
  38896. 'ꮴ' => '�',
  38897. 'ꮵ' => '�',
  38898. 'ꮶ' => '�',
  38899. 'ꮷ' => '�',
  38900. 'ꮸ' => '�',
  38901. 'ꮹ' => '�',
  38902. 'ꮺ' => '�',
  38903. 'ꮻ' => '�',
  38904. 'ꮼ' => '�',
  38905. 'ꮽ' => '�',
  38906. 'ꮾ' => '�',
  38907. 'ꮿ' => '�',
  38908. '�' => 'A',
  38909. 'b' => 'B',
  38910. 'c' => 'C',
  38911. 'd' => 'D',
  38912. 'ï½…' => 'ï¼¥',
  38913. 'f' => 'F',
  38914. 'g' => 'G',
  38915. 'h' => 'H',
  38916. 'i' => 'I',
  38917. 'j' => 'J',
  38918. 'k' => 'K',
  38919. 'l' => 'L',
  38920. '�' => 'M',
  38921. 'n' => 'N',
  38922. '�' => 'O',
  38923. '�' => 'P',
  38924. 'q' => 'Q',
  38925. 'ï½’' => 'ï¼²',
  38926. 's' => 'S',
  38927. 'ï½”' => 'ï¼´',
  38928. 'u' => 'U',
  38929. 'ï½–' => 'ï¼¶',
  38930. 'ï½—' => 'ï¼·',
  38931. 'x' => 'X',
  38932. 'ï½™' => 'ï¼¹',
  38933. 'z' => 'Z',
  38934. '�' => '�',
  38935. '�' => '�',
  38936. '�' => '�',
  38937. '�' => '�',
  38938. '�' => '�',
  38939. '�' => '�',
  38940. '�' => '�',
  38941. '�' => '�',
  38942. '�' => '�',
  38943. '�' => '�',
  38944. '�' => '�',
  38945. '�' => '�',
  38946. '�' => '�',
  38947. '�' => '�',
  38948. '�' => '�',
  38949. '�' => '�',
  38950. '�' => '�',
  38951. '�' => '�',
  38952. '�' => '�',
  38953. '�' => '�',
  38954. '�' => '�',
  38955. '�' => '�',
  38956. '�' => '�',
  38957. '�' => '�',
  38958. '�' => '�',
  38959. '�' => '�',
  38960. '�' => '�',
  38961. '�' => '�',
  38962. '�' => '�',
  38963. '�' => '�',
  38964. '�' => '�',
  38965. '�' => '�',
  38966. '�' => '�',
  38967. '�' => '�',
  38968. '�' => '�',
  38969. '�' => '�',
  38970. '�' => '�',
  38971. '�' => '�',
  38972. '�' => '�',
  38973. '�' => '�',
  38974. '�' => '�',
  38975. '�' => '�',
  38976. '�' => '�',
  38977. '�' => '�',
  38978. '�' => '�',
  38979. '�' => '�',
  38980. '�' => '�',
  38981. '�' => '�',
  38982. '�' => '�',
  38983. '�' => '�',
  38984. '�' => '�',
  38985. '�' => '�',
  38986. '�' => '�',
  38987. '�' => '�',
  38988. '�' => '�',
  38989. '�' => '�',
  38990. '�' => '�',
  38991. '�' => '�',
  38992. '�' => '�',
  38993. '�' => '�',
  38994. '�' => '�',
  38995. '�' => '�',
  38996. '�' => '�',
  38997. '�' => '�',
  38998. '�' => '�',
  38999. '�' => '�',
  39000. '�' => '�',
  39001. '�' => '�',
  39002. '�' => '�',
  39003. '�' => '�',
  39004. '�' => '�',
  39005. '�' => '�',
  39006. '�' => '�',
  39007. '�' => '�',
  39008. '�' => '�',
  39009. '�' => '�',
  39010. '�' => '�',
  39011. '�' => '�',
  39012. '�' => '�',
  39013. '�' => '�',
  39014. '�' => '�',
  39015. '�' => '�',
  39016. '�' => '�',
  39017. '�' => '�',
  39018. '�' => '�',
  39019. '�' => '�',
  39020. '�' => '�',
  39021. '�' => '�',
  39022. '�' => '�',
  39023. '�' => '�',
  39024. '�' => '�',
  39025. '�' => '�',
  39026. '�' => '�',
  39027. '�' => '�',
  39028. '�' => '�',
  39029. '�' => '�',
  39030. '�' => '�',
  39031. '�' => '�',
  39032. '�' => '�',
  39033. '�' => '�',
  39034. '�' => '�',
  39035. '�' => '�',
  39036. '�' => '�',
  39037. '�' => '�',
  39038. '�' => '�',
  39039. '�' => '�',
  39040. '�' => '�',
  39041. '�' => '�',
  39042. '�' => '�',
  39043. '�' => '�',
  39044. '�' => '�',
  39045. '�' => '�',
  39046. '�' => '�',
  39047. '�' => '�',
  39048. '�' => '�',
  39049. '�' => '�',
  39050. '�' => '�',
  39051. '�' => '�',
  39052. '�' => '�',
  39053. '�' => '�',
  39054. '�' => '�',
  39055. '�' => '�',
  39056. '�' => '�',
  39057. '�' => '�',
  39058. '�' => '�',
  39059. '�' => '�',
  39060. '�' => '�',
  39061. 'ð‘£€' => 'ð‘¢ ',
  39062. '�' => '𑢡',
  39063. '𑣂' => '𑢢',
  39064. '𑣃' => '𑢣',
  39065. '𑣄' => '𑢤',
  39066. 'ð‘£…' => 'ð‘¢¥',
  39067. '𑣆' => '𑢦',
  39068. '𑣇' => '𑢧',
  39069. '𑣈' => '𑢨',
  39070. '𑣉' => '𑢩',
  39071. '𑣊' => '𑢪',
  39072. '𑣋' => '𑢫',
  39073. '𑣌' => '𑢬',
  39074. '�' => '𑢭',
  39075. '𑣎' => '𑢮',
  39076. '�' => '𑢯',
  39077. '�' => '𑢰',
  39078. '𑣑' => '𑢱',
  39079. 'ð‘£’' => 'ð‘¢²',
  39080. '𑣓' => '𑢳',
  39081. 'ð‘£”' => 'ð‘¢´',
  39082. '𑣕' => '𑢵',
  39083. 'ð‘£–' => 'ð‘¢¶',
  39084. 'ð‘£—' => 'ð‘¢·',
  39085. '𑣘' => '𑢸',
  39086. 'ð‘£™' => 'ð‘¢¹',
  39087. '𑣚' => '𑢺',
  39088. 'ð‘£›' => 'ð‘¢»',
  39089. '𑣜' => '𑢼',
  39090. '�' => '𑢽',
  39091. '𑣞' => '𑢾',
  39092. '𑣟' => '𑢿',
  39093. 'ð–¹ ' => 'ð–¹€',
  39094. '𖹡' => '�',
  39095. '𖹢' => '𖹂',
  39096. '𖹣' => '𖹃',
  39097. '𖹤' => '𖹄',
  39098. 'ð–¹¥' => 'ð–¹…',
  39099. '𖹦' => '𖹆',
  39100. '𖹧' => '𖹇',
  39101. '𖹨' => '𖹈',
  39102. '𖹩' => '𖹉',
  39103. '𖹪' => '𖹊',
  39104. '𖹫' => '𖹋',
  39105. '𖹬' => '𖹌',
  39106. '𖹭' => '�',
  39107. '𖹮' => '𖹎',
  39108. '𖹯' => '�',
  39109. '𖹰' => '�',
  39110. '𖹱' => '𖹑',
  39111. 'ð–¹²' => 'ð–¹’',
  39112. '𖹳' => '𖹓',
  39113. 'ð–¹´' => 'ð–¹”',
  39114. '𖹵' => '𖹕',
  39115. 'ð–¹¶' => 'ð–¹–',
  39116. 'ð–¹·' => 'ð–¹—',
  39117. '𖹸' => '𖹘',
  39118. 'ð–¹¹' => 'ð–¹™',
  39119. '𖹺' => '𖹚',
  39120. 'ð–¹»' => 'ð–¹›',
  39121. '𖹼' => '𖹜',
  39122. '𖹽' => '�',
  39123. '𖹾' => '𖹞',
  39124. '𖹿' => '𖹟',
  39125. '𞤢' => '𞤀',
  39126. '𞤣' => '�',
  39127. '𞤤' => '𞤂',
  39128. '𞤥' => '𞤃',
  39129. '𞤦' => '𞤄',
  39130. '𞤧' => '𞤅',
  39131. '𞤨' => '𞤆',
  39132. '𞤩' => '𞤇',
  39133. '𞤪' => '𞤈',
  39134. '𞤫' => '𞤉',
  39135. '𞤬' => '𞤊',
  39136. '𞤭' => '𞤋',
  39137. '𞤮' => '𞤌',
  39138. '𞤯' => '�',
  39139. '𞤰' => '𞤎',
  39140. '𞤱' => '�',
  39141. '𞤲' => '�',
  39142. '𞤳' => '𞤑',
  39143. '𞤴' => '𞤒',
  39144. '𞤵' => '𞤓',
  39145. '𞤶' => '𞤔',
  39146. '𞤷' => '𞤕',
  39147. '𞤸' => '𞤖',
  39148. '𞤹' => '𞤗',
  39149. '𞤺' => '𞤘',
  39150. '𞤻' => '𞤙',
  39151. '𞤼' => '𞤚',
  39152. '𞤽' => '𞤛',
  39153. '𞤾' => '𞤜',
  39154. '𞤿' => '�',
  39155. '𞥀' => '𞤞',
  39156. '�' => '𞤟',
  39157. '𞥂' => '𞤠',
  39158. '𞥃' => '𞤡',
  39159. 'ß' => 'SS',
  39160. 'ff' => 'FF',
  39161. '�' => 'FI',
  39162. 'fl' => 'FL',
  39163. 'ffi' => 'FFI',
  39164. 'ffl' => 'FFL',
  39165. 'ſt' => 'ST',
  39166. 'st' => 'ST',
  39167. 'Ö‡' => 'ÔµÕ’',
  39168. 'ﬓ' => 'ՄՆ',
  39169. 'ﬔ' => 'ՄԵ',
  39170. 'ﬕ' => 'ՄԻ',
  39171. 'ﬖ' => 'ՎՆ',
  39172. 'ﬗ' => 'ՄԽ',
  39173. 'ʼn' => 'ʼN',
  39174. '�' => 'Ϊ�',
  39175. 'ΰ' => 'Ϋ�',
  39176. 'ǰ' => 'J̌',
  39177. 'ẖ' => 'H̱',
  39178. 'ẗ' => 'T̈',
  39179. 'ẘ' => 'W̊',
  39180. 'ẙ' => 'Y̊',
  39181. 'ẚ' => 'Aʾ',
  39182. '�' => 'Υ̓',
  39183. 'ὒ' => 'Υ̓̀',
  39184. 'ὔ' => 'Υ̓�',
  39185. 'ὖ' => 'Υ̓͂',
  39186. 'ᾶ' => 'Α͂',
  39187. 'ῆ' => 'Η͂',
  39188. 'ῒ' => 'Ϊ̀',
  39189. 'ΐ' => 'Ϊ�',
  39190. 'ῖ' => 'Ι͂',
  39191. 'ῗ' => 'Ϊ͂',
  39192. 'ῢ' => 'Ϋ̀',
  39193. 'ΰ' => 'Ϋ�',
  39194. 'ῤ' => 'Ρ̓',
  39195. 'ῦ' => 'Υ͂',
  39196. 'ῧ' => 'Ϋ͂',
  39197. 'ῶ' => 'Ω͂',
  39198. 'ᾈ' => 'ἈΙ',
  39199. 'ᾉ' => 'ἉΙ',
  39200. 'ᾊ' => 'ἊΙ',
  39201. 'ᾋ' => 'ἋΙ',
  39202. 'ᾌ' => 'ἌΙ',
  39203. '�' => '�Ι',
  39204. 'ᾎ' => 'ἎΙ',
  39205. '�' => '�Ι',
  39206. 'ᾘ' => 'ἨΙ',
  39207. 'ᾙ' => 'ἩΙ',
  39208. 'ᾚ' => 'ἪΙ',
  39209. 'ᾛ' => 'ἫΙ',
  39210. 'ᾜ' => 'ἬΙ',
  39211. '�' => 'ἭΙ',
  39212. 'ᾞ' => 'ἮΙ',
  39213. 'ᾟ' => 'ἯΙ',
  39214. 'ᾨ' => 'ὨΙ',
  39215. 'ᾩ' => 'ὩΙ',
  39216. 'ᾪ' => 'ὪΙ',
  39217. 'ᾫ' => 'ὫΙ',
  39218. 'ᾬ' => 'ὬΙ',
  39219. 'ᾭ' => 'ὭΙ',
  39220. 'ᾮ' => 'ὮΙ',
  39221. 'ᾯ' => 'ὯΙ',
  39222. 'ᾼ' => 'ΑΙ',
  39223. 'ῌ' => 'ΗΙ',
  39224. 'ῼ' => 'ΩΙ',
  39225. 'ᾲ' => 'ᾺΙ',
  39226. 'ᾴ' => 'ΆΙ',
  39227. 'ῂ' => 'ῊΙ',
  39228. 'ῄ' => 'ΉΙ',
  39229. 'ῲ' => 'ῺΙ',
  39230. 'ῴ' => '�Ι',
  39231. 'ᾷ' => 'Α͂Ι',
  39232. 'ῇ' => 'Η͂Ι',
  39233. 'ῷ' => 'Ω͂Ι',
  39234. );
  39235. <?php
  39236. namespace Symfony\Polyfill\Mbstring;
  39237. final class Mbstring
  39238. {
  39239. public const MB_CASE_FOLD = \PHP_INT_MAX;
  39240. private const SIMPLE_CASE_FOLD = [
  39241. ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
  39242. ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', '�', 'ε', "\xE1\xB9\xA1", 'ι'],
  39243. ];
  39244. private static $encodingList = ['ASCII', 'UTF-8'];
  39245. private static $language = 'neutral';
  39246. private static $internalEncoding = 'UTF-8';
  39247. public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
  39248. {
  39249. if (\is_array($s)) {
  39250. $r = [];
  39251. foreach ($s as $str) {
  39252. $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);
  39253. }
  39254. return $r;
  39255. }
  39256. if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
  39257. $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
  39258. } else {
  39259. $fromEncoding = self::getEncoding($fromEncoding);
  39260. }
  39261. $toEncoding = self::getEncoding($toEncoding);
  39262. if ('BASE64' === $fromEncoding) {
  39263. $s = base64_decode($s);
  39264. $fromEncoding = $toEncoding;
  39265. }
  39266. if ('BASE64' === $toEncoding) {
  39267. return base64_encode($s);
  39268. }
  39269. if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
  39270. if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
  39271. $fromEncoding = 'Windows-1252';
  39272. }
  39273. if ('UTF-8' !== $fromEncoding) {
  39274. $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
  39275. }
  39276. return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
  39277. }
  39278. if ('HTML-ENTITIES' === $fromEncoding) {
  39279. $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
  39280. $fromEncoding = 'UTF-8';
  39281. }
  39282. return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
  39283. }
  39284. public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
  39285. {
  39286. $ok = true;
  39287. array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
  39288. if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
  39289. $ok = false;
  39290. }
  39291. });
  39292. return $ok ? $fromEncoding : false;
  39293. }
  39294. public static function mb_decode_mimeheader($s)
  39295. {
  39296. return iconv_mime_decode($s, 2, self::$internalEncoding);
  39297. }
  39298. public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
  39299. {
  39300. trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
  39301. }
  39302. public static function mb_decode_numericentity($s, $convmap, $encoding = null)
  39303. {
  39304. if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
  39305. trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
  39306. return null;
  39307. }
  39308. if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
  39309. return false;
  39310. }
  39311. if (null !== $encoding && !\is_scalar($encoding)) {
  39312. trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
  39313. return '';
  39314. }
  39315. $s = (string) $s;
  39316. if ('' === $s) {
  39317. return '';
  39318. }
  39319. $encoding = self::getEncoding($encoding);
  39320. if ('UTF-8' === $encoding) {
  39321. $encoding = null;
  39322. if (!preg_match('//u', $s)) {
  39323. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  39324. }
  39325. } else {
  39326. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  39327. }
  39328. $cnt = floor(\count($convmap) / 4) * 4;
  39329. for ($i = 0; $i < $cnt; $i += 4) {
  39330. $convmap[$i] += $convmap[$i + 2];
  39331. $convmap[$i + 1] += $convmap[$i + 2];
  39332. }
  39333. $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
  39334. $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
  39335. for ($i = 0; $i < $cnt; $i += 4) {
  39336. if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
  39337. return self::mb_chr($c - $convmap[$i + 2]);
  39338. }
  39339. }
  39340. return $m[0];
  39341. }, $s);
  39342. if (null === $encoding) {
  39343. return $s;
  39344. }
  39345. return iconv('UTF-8', $encoding.'//IGNORE', $s);
  39346. }
  39347. public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
  39348. {
  39349. if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
  39350. trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
  39351. return null;
  39352. }
  39353. if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
  39354. return false;
  39355. }
  39356. if (null !== $encoding && !\is_scalar($encoding)) {
  39357. trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
  39358. return null;
  39359. }
  39360. if (null !== $is_hex && !\is_scalar($is_hex)) {
  39361. trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
  39362. return null;
  39363. }
  39364. $s = (string) $s;
  39365. if ('' === $s) {
  39366. return '';
  39367. }
  39368. $encoding = self::getEncoding($encoding);
  39369. if ('UTF-8' === $encoding) {
  39370. $encoding = null;
  39371. if (!preg_match('//u', $s)) {
  39372. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  39373. }
  39374. } else {
  39375. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  39376. }
  39377. static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
  39378. $cnt = floor(\count($convmap) / 4) * 4;
  39379. $i = 0;
  39380. $len = \strlen($s);
  39381. $result = '';
  39382. while ($i < $len) {
  39383. $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
  39384. $uchr = substr($s, $i, $ulen);
  39385. $i += $ulen;
  39386. $c = self::mb_ord($uchr);
  39387. for ($j = 0; $j < $cnt; $j += 4) {
  39388. if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
  39389. $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
  39390. $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
  39391. continue 2;
  39392. }
  39393. }
  39394. $result .= $uchr;
  39395. }
  39396. if (null === $encoding) {
  39397. return $result;
  39398. }
  39399. return iconv('UTF-8', $encoding.'//IGNORE', $result);
  39400. }
  39401. public static function mb_convert_case($s, $mode, $encoding = null)
  39402. {
  39403. $s = (string) $s;
  39404. if ('' === $s) {
  39405. return '';
  39406. }
  39407. $encoding = self::getEncoding($encoding);
  39408. if ('UTF-8' === $encoding) {
  39409. $encoding = null;
  39410. if (!preg_match('//u', $s)) {
  39411. $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
  39412. }
  39413. } else {
  39414. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  39415. }
  39416. if (\MB_CASE_TITLE == $mode) {
  39417. static $titleRegexp = null;
  39418. if (null === $titleRegexp) {
  39419. $titleRegexp = self::getData('titleCaseRegexp');
  39420. }
  39421. $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
  39422. } else {
  39423. if (\MB_CASE_UPPER == $mode) {
  39424. static $upper = null;
  39425. if (null === $upper) {
  39426. $upper = self::getData('upperCase');
  39427. }
  39428. $map = $upper;
  39429. } else {
  39430. if (self::MB_CASE_FOLD === $mode) {
  39431. static $caseFolding = null;
  39432. if (null === $caseFolding) {
  39433. $caseFolding = self::getData('caseFolding');
  39434. }
  39435. $s = strtr($s, $caseFolding);
  39436. }
  39437. static $lower = null;
  39438. if (null === $lower) {
  39439. $lower = self::getData('lowerCase');
  39440. }
  39441. $map = $lower;
  39442. }
  39443. static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
  39444. $i = 0;
  39445. $len = \strlen($s);
  39446. while ($i < $len) {
  39447. $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
  39448. $uchr = substr($s, $i, $ulen);
  39449. $i += $ulen;
  39450. if (isset($map[$uchr])) {
  39451. $uchr = $map[$uchr];
  39452. $nlen = \strlen($uchr);
  39453. if ($nlen == $ulen) {
  39454. $nlen = $i;
  39455. do {
  39456. $s[--$nlen] = $uchr[--$ulen];
  39457. } while ($ulen);
  39458. } else {
  39459. $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
  39460. $len += $nlen - $ulen;
  39461. $i += $nlen - $ulen;
  39462. }
  39463. }
  39464. }
  39465. }
  39466. if (null === $encoding) {
  39467. return $s;
  39468. }
  39469. return iconv('UTF-8', $encoding.'//IGNORE', $s);
  39470. }
  39471. public static function mb_internal_encoding($encoding = null)
  39472. {
  39473. if (null === $encoding) {
  39474. return self::$internalEncoding;
  39475. }
  39476. $normalizedEncoding = self::getEncoding($encoding);
  39477. if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
  39478. self::$internalEncoding = $normalizedEncoding;
  39479. return true;
  39480. }
  39481. if (80000 > \PHP_VERSION_ID) {
  39482. return false;
  39483. }
  39484. throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
  39485. }
  39486. public static function mb_language($lang = null)
  39487. {
  39488. if (null === $lang) {
  39489. return self::$language;
  39490. }
  39491. switch ($normalizedLang = strtolower($lang)) {
  39492. case 'uni':
  39493. case 'neutral':
  39494. self::$language = $normalizedLang;
  39495. return true;
  39496. }
  39497. if (80000 > \PHP_VERSION_ID) {
  39498. return false;
  39499. }
  39500. throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
  39501. }
  39502. public static function mb_list_encodings()
  39503. {
  39504. return ['UTF-8'];
  39505. }
  39506. public static function mb_encoding_aliases($encoding)
  39507. {
  39508. switch (strtoupper($encoding)) {
  39509. case 'UTF8':
  39510. case 'UTF-8':
  39511. return ['utf8'];
  39512. }
  39513. return false;
  39514. }
  39515. public static function mb_check_encoding($var = null, $encoding = null)
  39516. {
  39517. if (null === $encoding) {
  39518. if (null === $var) {
  39519. return false;
  39520. }
  39521. $encoding = self::$internalEncoding;
  39522. }
  39523. if (!\is_array($var)) {
  39524. return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
  39525. }
  39526. foreach ($var as $key => $value) {
  39527. if (!self::mb_check_encoding($key, $encoding)) {
  39528. return false;
  39529. }
  39530. if (!self::mb_check_encoding($value, $encoding)) {
  39531. return false;
  39532. }
  39533. }
  39534. return true;
  39535. }
  39536. public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
  39537. {
  39538. if (null === $encodingList) {
  39539. $encodingList = self::$encodingList;
  39540. } else {
  39541. if (!\is_array($encodingList)) {
  39542. $encodingList = array_map('trim', explode(',', $encodingList));
  39543. }
  39544. $encodingList = array_map('strtoupper', $encodingList);
  39545. }
  39546. foreach ($encodingList as $enc) {
  39547. switch ($enc) {
  39548. case 'ASCII':
  39549. if (!preg_match('/[\x80-\xFF]/', $str)) {
  39550. return $enc;
  39551. }
  39552. break;
  39553. case 'UTF8':
  39554. case 'UTF-8':
  39555. if (preg_match('//u', $str)) {
  39556. return 'UTF-8';
  39557. }
  39558. break;
  39559. default:
  39560. if (0 === strncmp($enc, 'ISO-8859-', 9)) {
  39561. return $enc;
  39562. }
  39563. }
  39564. }
  39565. return false;
  39566. }
  39567. public static function mb_detect_order($encodingList = null)
  39568. {
  39569. if (null === $encodingList) {
  39570. return self::$encodingList;
  39571. }
  39572. if (!\is_array($encodingList)) {
  39573. $encodingList = array_map('trim', explode(',', $encodingList));
  39574. }
  39575. $encodingList = array_map('strtoupper', $encodingList);
  39576. foreach ($encodingList as $enc) {
  39577. switch ($enc) {
  39578. default:
  39579. if (strncmp($enc, 'ISO-8859-', 9)) {
  39580. return false;
  39581. }
  39582. case 'ASCII':
  39583. case 'UTF8':
  39584. case 'UTF-8':
  39585. }
  39586. }
  39587. self::$encodingList = $encodingList;
  39588. return true;
  39589. }
  39590. public static function mb_strlen($s, $encoding = null)
  39591. {
  39592. $encoding = self::getEncoding($encoding);
  39593. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  39594. return \strlen($s);
  39595. }
  39596. return @iconv_strlen($s, $encoding);
  39597. }
  39598. public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
  39599. {
  39600. $encoding = self::getEncoding($encoding);
  39601. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  39602. return strpos($haystack, $needle, $offset);
  39603. }
  39604. $needle = (string) $needle;
  39605. if ('' === $needle) {
  39606. if (80000 > \PHP_VERSION_ID) {
  39607. trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
  39608. return false;
  39609. }
  39610. return 0;
  39611. }
  39612. return iconv_strpos($haystack, $needle, $offset, $encoding);
  39613. }
  39614. public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
  39615. {
  39616. $encoding = self::getEncoding($encoding);
  39617. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  39618. return strrpos($haystack, $needle, $offset);
  39619. }
  39620. if ($offset != (int) $offset) {
  39621. $offset = 0;
  39622. } elseif ($offset = (int) $offset) {
  39623. if ($offset < 0) {
  39624. if (0 > $offset += self::mb_strlen($needle)) {
  39625. $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
  39626. }
  39627. $offset = 0;
  39628. } else {
  39629. $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
  39630. }
  39631. }
  39632. $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
  39633. ? iconv_strrpos($haystack, $needle, $encoding)
  39634. : self::mb_strlen($haystack, $encoding);
  39635. return false !== $pos ? $offset + $pos : false;
  39636. }
  39637. public static function mb_str_split($string, $split_length = 1, $encoding = null)
  39638. {
  39639. if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
  39640. trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
  39641. return null;
  39642. }
  39643. if (1 > $split_length = (int) $split_length) {
  39644. if (80000 > \PHP_VERSION_ID) {
  39645. trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
  39646. return false;
  39647. }
  39648. throw new \ValueError('Argument #2 ($length) must be greater than 0');
  39649. }
  39650. if (null === $encoding) {
  39651. $encoding = mb_internal_encoding();
  39652. }
  39653. if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
  39654. $rx = '/(';
  39655. while (65535 < $split_length) {
  39656. $rx .= '.{65535}';
  39657. $split_length -= 65535;
  39658. }
  39659. $rx .= '.{'.$split_length.'})/us';
  39660. return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
  39661. }
  39662. $result = [];
  39663. $length = mb_strlen($string, $encoding);
  39664. for ($i = 0; $i < $length; $i += $split_length) {
  39665. $result[] = mb_substr($string, $i, $split_length, $encoding);
  39666. }
  39667. return $result;
  39668. }
  39669. public static function mb_strtolower($s, $encoding = null)
  39670. {
  39671. return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
  39672. }
  39673. public static function mb_strtoupper($s, $encoding = null)
  39674. {
  39675. return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
  39676. }
  39677. public static function mb_substitute_character($c = null)
  39678. {
  39679. if (null === $c) {
  39680. return 'none';
  39681. }
  39682. if (0 === strcasecmp($c, 'none')) {
  39683. return true;
  39684. }
  39685. if (80000 > \PHP_VERSION_ID) {
  39686. return false;
  39687. }
  39688. if (\is_int($c) || 'long' === $c || 'entity' === $c) {
  39689. return false;
  39690. }
  39691. throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
  39692. }
  39693. public static function mb_substr($s, $start, $length = null, $encoding = null)
  39694. {
  39695. $encoding = self::getEncoding($encoding);
  39696. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  39697. return (string) substr($s, $start, null === $length ? 2147483647 : $length);
  39698. }
  39699. if ($start < 0) {
  39700. $start = iconv_strlen($s, $encoding) + $start;
  39701. if ($start < 0) {
  39702. $start = 0;
  39703. }
  39704. }
  39705. if (null === $length) {
  39706. $length = 2147483647;
  39707. } elseif ($length < 0) {
  39708. $length = iconv_strlen($s, $encoding) + $length - $start;
  39709. if ($length < 0) {
  39710. return '';
  39711. }
  39712. }
  39713. return (string) iconv_substr($s, $start, $length, $encoding);
  39714. }
  39715. public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
  39716. {
  39717. [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
  39718. self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
  39719. self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
  39720. ]);
  39721. return self::mb_strpos($haystack, $needle, $offset, $encoding);
  39722. }
  39723. public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
  39724. {
  39725. $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
  39726. return self::getSubpart($pos, $part, $haystack, $encoding);
  39727. }
  39728. public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
  39729. {
  39730. $encoding = self::getEncoding($encoding);
  39731. if ('CP850' === $encoding || 'ASCII' === $encoding) {
  39732. $pos = strrpos($haystack, $needle);
  39733. } else {
  39734. $needle = self::mb_substr($needle, 0, 1, $encoding);
  39735. $pos = iconv_strrpos($haystack, $needle, $encoding);
  39736. }
  39737. return self::getSubpart($pos, $part, $haystack, $encoding);
  39738. }
  39739. public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
  39740. {
  39741. $needle = self::mb_substr($needle, 0, 1, $encoding);
  39742. $pos = self::mb_strripos($haystack, $needle, $encoding);
  39743. return self::getSubpart($pos, $part, $haystack, $encoding);
  39744. }
  39745. public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
  39746. {
  39747. $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
  39748. $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
  39749. $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
  39750. $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
  39751. return self::mb_strrpos($haystack, $needle, $offset, $encoding);
  39752. }
  39753. public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
  39754. {
  39755. $pos = strpos($haystack, $needle);
  39756. if (false === $pos) {
  39757. return false;
  39758. }
  39759. if ($part) {
  39760. return substr($haystack, 0, $pos);
  39761. }
  39762. return substr($haystack, $pos);
  39763. }
  39764. public static function mb_get_info($type = 'all')
  39765. {
  39766. $info = [
  39767. 'internal_encoding' => self::$internalEncoding,
  39768. 'http_output' => 'pass',
  39769. 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
  39770. 'func_overload' => 0,
  39771. 'func_overload_list' => 'no overload',
  39772. 'mail_charset' => 'UTF-8',
  39773. 'mail_header_encoding' => 'BASE64',
  39774. 'mail_body_encoding' => 'BASE64',
  39775. 'illegal_chars' => 0,
  39776. 'encoding_translation' => 'Off',
  39777. 'language' => self::$language,
  39778. 'detect_order' => self::$encodingList,
  39779. 'substitute_character' => 'none',
  39780. 'strict_detection' => 'Off',
  39781. ];
  39782. if ('all' === $type) {
  39783. return $info;
  39784. }
  39785. if (isset($info[$type])) {
  39786. return $info[$type];
  39787. }
  39788. return false;
  39789. }
  39790. public static function mb_http_input($type = '')
  39791. {
  39792. return false;
  39793. }
  39794. public static function mb_http_output($encoding = null)
  39795. {
  39796. return null !== $encoding ? 'pass' === $encoding : 'pass';
  39797. }
  39798. public static function mb_strwidth($s, $encoding = null)
  39799. {
  39800. $encoding = self::getEncoding($encoding);
  39801. if ('UTF-8' !== $encoding) {
  39802. $s = iconv($encoding, 'UTF-8//IGNORE', $s);
  39803. }
  39804. $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
  39805. return ($wide << 1) + iconv_strlen($s, 'UTF-8');
  39806. }
  39807. public static function mb_substr_count($haystack, $needle, $encoding = null)
  39808. {
  39809. return substr_count($haystack, $needle);
  39810. }
  39811. public static function mb_output_handler($contents, $status)
  39812. {
  39813. return $contents;
  39814. }
  39815. public static function mb_chr($code, $encoding = null)
  39816. {
  39817. if (0x80 > $code %= 0x200000) {
  39818. $s = \chr($code);
  39819. } elseif (0x800 > $code) {
  39820. $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
  39821. } elseif (0x10000 > $code) {
  39822. $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  39823. } else {
  39824. $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
  39825. }
  39826. if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
  39827. $s = mb_convert_encoding($s, $encoding, 'UTF-8');
  39828. }
  39829. return $s;
  39830. }
  39831. public static function mb_ord($s, $encoding = null)
  39832. {
  39833. if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
  39834. $s = mb_convert_encoding($s, 'UTF-8', $encoding);
  39835. }
  39836. if (1 === \strlen($s)) {
  39837. return \ord($s);
  39838. }
  39839. $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
  39840. if (0xF0 <= $code) {
  39841. return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
  39842. }
  39843. if (0xE0 <= $code) {
  39844. return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
  39845. }
  39846. if (0xC0 <= $code) {
  39847. return (($code - 0xC0) << 6) + $s[2] - 0x80;
  39848. }
  39849. return $code;
  39850. }
  39851. public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
  39852. {
  39853. if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
  39854. throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
  39855. }
  39856. if (null === $encoding) {
  39857. $encoding = self::mb_internal_encoding();
  39858. } else {
  39859. self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given');
  39860. }
  39861. if (self::mb_strlen($pad_string, $encoding) <= 0) {
  39862. throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
  39863. }
  39864. $paddingRequired = $length - self::mb_strlen($string, $encoding);
  39865. if ($paddingRequired < 1) {
  39866. return $string;
  39867. }
  39868. switch ($pad_type) {
  39869. case \STR_PAD_LEFT:
  39870. return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
  39871. case \STR_PAD_RIGHT:
  39872. return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
  39873. default:
  39874. $leftPaddingLength = floor($paddingRequired / 2);
  39875. $rightPaddingLength = $paddingRequired - $leftPaddingLength;
  39876. return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
  39877. }
  39878. }
  39879. public static function mb_ucfirst(string $string, ?string $encoding = null): string
  39880. {
  39881. if (null === $encoding) {
  39882. $encoding = self::mb_internal_encoding();
  39883. } else {
  39884. self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
  39885. }
  39886. $firstChar = mb_substr($string, 0, 1, $encoding);
  39887. $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding);
  39888. return $firstChar.mb_substr($string, 1, null, $encoding);
  39889. }
  39890. public static function mb_lcfirst(string $string, ?string $encoding = null): string
  39891. {
  39892. if (null === $encoding) {
  39893. $encoding = self::mb_internal_encoding();
  39894. } else {
  39895. self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
  39896. }
  39897. $firstChar = mb_substr($string, 0, 1, $encoding);
  39898. $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding);
  39899. return $firstChar.mb_substr($string, 1, null, $encoding);
  39900. }
  39901. private static function getSubpart($pos, $part, $haystack, $encoding)
  39902. {
  39903. if (false === $pos) {
  39904. return false;
  39905. }
  39906. if ($part) {
  39907. return self::mb_substr($haystack, 0, $pos, $encoding);
  39908. }
  39909. return self::mb_substr($haystack, $pos, null, $encoding);
  39910. }
  39911. private static function html_encoding_callback(array $m)
  39912. {
  39913. $i = 1;
  39914. $entities = '';
  39915. $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
  39916. while (isset($m[$i])) {
  39917. if (0x80 > $m[$i]) {
  39918. $entities .= \chr($m[$i++]);
  39919. continue;
  39920. }
  39921. if (0xF0 <= $m[$i]) {
  39922. $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
  39923. } elseif (0xE0 <= $m[$i]) {
  39924. $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
  39925. } else {
  39926. $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
  39927. }
  39928. $entities .= '&#'.$c.';';
  39929. }
  39930. return $entities;
  39931. }
  39932. private static function title_case(array $s)
  39933. {
  39934. return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
  39935. }
  39936. private static function getData($file)
  39937. {
  39938. if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
  39939. return require $file;
  39940. }
  39941. return false;
  39942. }
  39943. private static function getEncoding($encoding)
  39944. {
  39945. if (null === $encoding) {
  39946. return self::$internalEncoding;
  39947. }
  39948. if ('UTF-8' === $encoding) {
  39949. return 'UTF-8';
  39950. }
  39951. $encoding = strtoupper($encoding);
  39952. if ('8BIT' === $encoding || 'BINARY' === $encoding) {
  39953. return 'CP850';
  39954. }
  39955. if ('UTF8' === $encoding) {
  39956. return 'UTF-8';
  39957. }
  39958. return $encoding;
  39959. }
  39960. public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
  39961. {
  39962. return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
  39963. }
  39964. public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
  39965. {
  39966. return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
  39967. }
  39968. public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
  39969. {
  39970. return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
  39971. }
  39972. private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string
  39973. {
  39974. if (null === $encoding) {
  39975. $encoding = self::mb_internal_encoding();
  39976. } else {
  39977. self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given');
  39978. }
  39979. if ('' === $characters) {
  39980. return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding);
  39981. }
  39982. if ('UTF-8' === $encoding) {
  39983. $encoding = null;
  39984. if (!preg_match('//u', $string)) {
  39985. $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string);
  39986. }
  39987. if (null !== $characters && !preg_match('//u', $characters)) {
  39988. $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters);
  39989. }
  39990. } else {
  39991. $string = iconv($encoding, 'UTF-8//IGNORE', $string);
  39992. if (null !== $characters) {
  39993. $characters = iconv($encoding, 'UTF-8//IGNORE', $characters);
  39994. }
  39995. }
  39996. if (null === $characters) {
  39997. $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}";
  39998. } else {
  39999. $characters = preg_quote($characters);
  40000. }
  40001. $string = preg_replace(sprintf($regex, $characters), '', $string);
  40002. if (null === $encoding) {
  40003. return $string;
  40004. }
  40005. return iconv('UTF-8', $encoding.'//IGNORE', $string);
  40006. }
  40007. private static function assertEncoding(string $encoding, string $errorFormat): void
  40008. {
  40009. try {
  40010. $validEncoding = @self::mb_check_encoding('', $encoding);
  40011. } catch (\ValueError $e) {
  40012. throw new \ValueError(sprintf($errorFormat, $encoding));
  40013. }
  40014. if (!$validEncoding) {
  40015. throw new \ValueError(sprintf($errorFormat, $encoding));
  40016. }
  40017. }
  40018. }
  40019. <?php
  40020. use Symfony\Polyfill\Mbstring as p;
  40021. if (\PHP_VERSION_ID >= 80000) {
  40022. return require __DIR__.'/bootstrap80.php';
  40023. }
  40024. if (!function_exists('mb_convert_encoding')) {
  40025. function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
  40026. }
  40027. if (!function_exists('mb_decode_mimeheader')) {
  40028. function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
  40029. }
  40030. if (!function_exists('mb_encode_mimeheader')) {
  40031. function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
  40032. }
  40033. if (!function_exists('mb_decode_numericentity')) {
  40034. function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
  40035. }
  40036. if (!function_exists('mb_encode_numericentity')) {
  40037. function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
  40038. }
  40039. if (!function_exists('mb_convert_case')) {
  40040. function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
  40041. }
  40042. if (!function_exists('mb_internal_encoding')) {
  40043. function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
  40044. }
  40045. if (!function_exists('mb_language')) {
  40046. function mb_language($language = null) { return p\Mbstring::mb_language($language); }
  40047. }
  40048. if (!function_exists('mb_list_encodings')) {
  40049. function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
  40050. }
  40051. if (!function_exists('mb_encoding_aliases')) {
  40052. function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
  40053. }
  40054. if (!function_exists('mb_check_encoding')) {
  40055. function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
  40056. }
  40057. if (!function_exists('mb_detect_encoding')) {
  40058. function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
  40059. }
  40060. if (!function_exists('mb_detect_order')) {
  40061. function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
  40062. }
  40063. if (!function_exists('mb_parse_str')) {
  40064. function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
  40065. }
  40066. if (!function_exists('mb_strlen')) {
  40067. function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
  40068. }
  40069. if (!function_exists('mb_strpos')) {
  40070. function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
  40071. }
  40072. if (!function_exists('mb_strtolower')) {
  40073. function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
  40074. }
  40075. if (!function_exists('mb_strtoupper')) {
  40076. function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
  40077. }
  40078. if (!function_exists('mb_substitute_character')) {
  40079. function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
  40080. }
  40081. if (!function_exists('mb_substr')) {
  40082. function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
  40083. }
  40084. if (!function_exists('mb_stripos')) {
  40085. function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
  40086. }
  40087. if (!function_exists('mb_stristr')) {
  40088. function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
  40089. }
  40090. if (!function_exists('mb_strrchr')) {
  40091. function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
  40092. }
  40093. if (!function_exists('mb_strrichr')) {
  40094. function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
  40095. }
  40096. if (!function_exists('mb_strripos')) {
  40097. function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
  40098. }
  40099. if (!function_exists('mb_strrpos')) {
  40100. function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
  40101. }
  40102. if (!function_exists('mb_strstr')) {
  40103. function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
  40104. }
  40105. if (!function_exists('mb_get_info')) {
  40106. function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
  40107. }
  40108. if (!function_exists('mb_http_output')) {
  40109. function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
  40110. }
  40111. if (!function_exists('mb_strwidth')) {
  40112. function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
  40113. }
  40114. if (!function_exists('mb_substr_count')) {
  40115. function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
  40116. }
  40117. if (!function_exists('mb_output_handler')) {
  40118. function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
  40119. }
  40120. if (!function_exists('mb_http_input')) {
  40121. function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
  40122. }
  40123. if (!function_exists('mb_convert_variables')) {
  40124. function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
  40125. }
  40126. if (!function_exists('mb_ord')) {
  40127. function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
  40128. }
  40129. if (!function_exists('mb_chr')) {
  40130. function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
  40131. }
  40132. if (!function_exists('mb_scrub')) {
  40133. function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
  40134. }
  40135. if (!function_exists('mb_str_split')) {
  40136. function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
  40137. }
  40138. if (!function_exists('mb_str_pad')) {
  40139. function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
  40140. }
  40141. if (!function_exists('mb_ucfirst')) {
  40142. function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
  40143. }
  40144. if (!function_exists('mb_lcfirst')) {
  40145. function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
  40146. }
  40147. if (!function_exists('mb_trim')) {
  40148. function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
  40149. }
  40150. if (!function_exists('mb_ltrim')) {
  40151. function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
  40152. }
  40153. if (!function_exists('mb_rtrim')) {
  40154. function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
  40155. }
  40156. if (extension_loaded('mbstring')) {
  40157. return;
  40158. }
  40159. if (!defined('MB_CASE_UPPER')) {
  40160. define('MB_CASE_UPPER', 0);
  40161. }
  40162. if (!defined('MB_CASE_LOWER')) {
  40163. define('MB_CASE_LOWER', 1);
  40164. }
  40165. if (!defined('MB_CASE_TITLE')) {
  40166. define('MB_CASE_TITLE', 2);
  40167. }
  40168. <?php
  40169. use Symfony\Polyfill\Intl\Grapheme as p;
  40170. if (!defined('GRAPHEME_EXTR_COUNT')) {
  40171. define('GRAPHEME_EXTR_COUNT', 0);
  40172. }
  40173. if (!defined('GRAPHEME_EXTR_MAXBYTES')) {
  40174. define('GRAPHEME_EXTR_MAXBYTES', 1);
  40175. }
  40176. if (!defined('GRAPHEME_EXTR_MAXCHARS')) {
  40177. define('GRAPHEME_EXTR_MAXCHARS', 2);
  40178. }
  40179. if (!function_exists('grapheme_extract')) {
  40180. function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); }
  40181. }
  40182. if (!function_exists('grapheme_stripos')) {
  40183. function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); }
  40184. }
  40185. if (!function_exists('grapheme_stristr')) {
  40186. function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }
  40187. }
  40188. if (!function_exists('grapheme_strlen')) {
  40189. function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); }
  40190. }
  40191. if (!function_exists('grapheme_strpos')) {
  40192. function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); }
  40193. }
  40194. if (!function_exists('grapheme_strripos')) {
  40195. function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); }
  40196. }
  40197. if (!function_exists('grapheme_strrpos')) {
  40198. function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); }
  40199. }
  40200. if (!function_exists('grapheme_strstr')) {
  40201. function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }
  40202. }
  40203. if (!function_exists('grapheme_substr')) {
  40204. function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); }
  40205. }
  40206. <?php
  40207. namespace Symfony\Polyfill\Intl\Grapheme;
  40208. \define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\X' : Grapheme::GRAPHEME_CLUSTER_RX);
  40209. final class Grapheme
  40210. {
  40211. public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴�구궈궤귀규그긔기까깨꺄꺠꺼께껴�꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨���나내�냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴�늬니다대댜댸��뎌뎨������둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴�똬뙈뙤뚀뚜뚸뛔뛰뜌뜨���래랴�러레려례로롸뢔뢰료루뤄뤠뤼류르�리마매먀먜머메며몌모뫄뫠뫼묘무�뭬뮈뮤므믜미바배뱌뱨버베벼볘보�봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴�뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼���사새샤섀서세셔셰소솨쇄쇠쇼수숴�쉬슈스싀시싸쌔쌰��쎄쎠쎼����쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어�여예오와왜외요우워웨위유으���재쟈쟤저제져졔조좌좨죄죠주줘줴�쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴�쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체�쳬초촤쵀최쵸추춰췌취츄츠츼치카�캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴��킈키타태탸턔터테텨톄토톼퇘퇴�투퉈퉤튀튜트틔티파패���페펴����푀표푸풔풰퓌퓨프픠피하해�햬허헤혀혜호화홰회효후훠훼휘휴��히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])';
  40212. private const CASE_FOLD = [
  40213. ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
  40214. ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', '�', 'ε', "\xE1\xB9\xA1", 'ι'],
  40215. ];
  40216. public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0)
  40217. {
  40218. if (0 > $start) {
  40219. $start = \strlen($s) + $start;
  40220. }
  40221. if (!\is_scalar($s)) {
  40222. $hasError = false;
  40223. set_error_handler(function () use (&$hasError) { $hasError = true; });
  40224. $next = substr($s, $start);
  40225. restore_error_handler();
  40226. if ($hasError) {
  40227. substr($s, $start);
  40228. $s = '';
  40229. } else {
  40230. $s = $next;
  40231. }
  40232. } else {
  40233. $s = substr($s, $start);
  40234. }
  40235. $size = (int) $size;
  40236. $type = (int) $type;
  40237. $start = (int) $start;
  40238. if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) {
  40239. if (80000 > \PHP_VERSION_ID) {
  40240. return false;
  40241. }
  40242. throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS');
  40243. }
  40244. if (!isset($s[0]) || 0 > $size || 0 > $start) {
  40245. return false;
  40246. }
  40247. if (0 === $size) {
  40248. return '';
  40249. }
  40250. $next = $start;
  40251. $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE);
  40252. if (!isset($s[1])) {
  40253. return false;
  40254. }
  40255. $i = 1;
  40256. $ret = '';
  40257. do {
  40258. if (\GRAPHEME_EXTR_COUNT === $type) {
  40259. --$size;
  40260. } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) {
  40261. $size -= \strlen($s[$i]);
  40262. } else {
  40263. $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE');
  40264. }
  40265. if ($size >= 0) {
  40266. $ret .= $s[$i];
  40267. }
  40268. } while (isset($s[++$i]) && $size > 0);
  40269. $next += \strlen($ret);
  40270. return $ret;
  40271. }
  40272. public static function grapheme_strlen($s)
  40273. {
  40274. preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len);
  40275. return 0 === $len && '' !== $s ? null : $len;
  40276. }
  40277. public static function grapheme_substr($s, $start, $len = null)
  40278. {
  40279. if (null === $len) {
  40280. $len = 2147483647;
  40281. }
  40282. preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s);
  40283. $slen = \count($s[0]);
  40284. $start = (int) $start;
  40285. if (0 > $start) {
  40286. $start += $slen;
  40287. }
  40288. if (0 > $start) {
  40289. if (\PHP_VERSION_ID < 80000) {
  40290. return false;
  40291. }
  40292. $start = 0;
  40293. }
  40294. if ($start >= $slen) {
  40295. return \PHP_VERSION_ID >= 80000 ? '' : false;
  40296. }
  40297. $rem = $slen - $start;
  40298. if (0 > $len) {
  40299. $len += $rem;
  40300. }
  40301. if (0 === $len) {
  40302. return '';
  40303. }
  40304. if (0 > $len) {
  40305. return \PHP_VERSION_ID >= 80000 ? '' : false;
  40306. }
  40307. if ($len > $rem) {
  40308. $len = $rem;
  40309. }
  40310. return implode('', \array_slice($s[0], $start, $len));
  40311. }
  40312. public static function grapheme_strpos($s, $needle, $offset = 0)
  40313. {
  40314. return self::grapheme_position($s, $needle, $offset, 0);
  40315. }
  40316. public static function grapheme_stripos($s, $needle, $offset = 0)
  40317. {
  40318. return self::grapheme_position($s, $needle, $offset, 1);
  40319. }
  40320. public static function grapheme_strrpos($s, $needle, $offset = 0)
  40321. {
  40322. return self::grapheme_position($s, $needle, $offset, 2);
  40323. }
  40324. public static function grapheme_strripos($s, $needle, $offset = 0)
  40325. {
  40326. return self::grapheme_position($s, $needle, $offset, 3);
  40327. }
  40328. public static function grapheme_stristr($s, $needle, $beforeNeedle = false)
  40329. {
  40330. return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8');
  40331. }
  40332. public static function grapheme_strstr($s, $needle, $beforeNeedle = false)
  40333. {
  40334. return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8');
  40335. }
  40336. private static function grapheme_position($s, $needle, $offset, $mode)
  40337. {
  40338. $needle = (string) $needle;
  40339. if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) {
  40340. return false;
  40341. }
  40342. $s = (string) $s;
  40343. if (!preg_match('/./us', $s)) {
  40344. return false;
  40345. }
  40346. if ($offset > 0) {
  40347. $s = self::grapheme_substr($s, $offset);
  40348. } elseif ($offset < 0) {
  40349. if (2 > $mode) {
  40350. $offset += self::grapheme_strlen($s);
  40351. $s = self::grapheme_substr($s, $offset);
  40352. if (0 > $offset) {
  40353. $offset = 0;
  40354. }
  40355. } elseif (0 > $offset += self::grapheme_strlen($needle)) {
  40356. $s = self::grapheme_substr($s, 0, $offset);
  40357. $offset = 0;
  40358. } else {
  40359. $offset = 0;
  40360. }
  40361. }
  40362. $caseInsensitive = $mode & 1;
  40363. $reverse = $mode & 2;
  40364. if ($caseInsensitive) {
  40365. $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER;
  40366. $s = mb_convert_case($s, $mode, 'UTF-8');
  40367. $needle = mb_convert_case($needle, $mode, 'UTF-8');
  40368. if (!\defined('MB_CASE_FOLD_SIMPLE')) {
  40369. $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
  40370. $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle);
  40371. }
  40372. }
  40373. if ($reverse) {
  40374. $needlePos = strrpos($s, $needle);
  40375. } else {
  40376. $needlePos = strpos($s, $needle);
  40377. }
  40378. return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false;
  40379. }
  40380. }
  40381. <?php
  40382. use Symfony\Polyfill\Intl\Grapheme as p;
  40383. if (extension_loaded('intl')) {
  40384. return;
  40385. }
  40386. if (\PHP_VERSION_ID >= 80000) {
  40387. return require __DIR__.'/bootstrap80.php';
  40388. }
  40389. if (!defined('GRAPHEME_EXTR_COUNT')) {
  40390. define('GRAPHEME_EXTR_COUNT', 0);
  40391. }
  40392. if (!defined('GRAPHEME_EXTR_MAXBYTES')) {
  40393. define('GRAPHEME_EXTR_MAXBYTES', 1);
  40394. }
  40395. if (!defined('GRAPHEME_EXTR_MAXCHARS')) {
  40396. define('GRAPHEME_EXTR_MAXCHARS', 2);
  40397. }
  40398. if (!function_exists('grapheme_extract')) {
  40399. function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); }
  40400. }
  40401. if (!function_exists('grapheme_stripos')) {
  40402. function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); }
  40403. }
  40404. if (!function_exists('grapheme_stristr')) {
  40405. function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); }
  40406. }
  40407. if (!function_exists('grapheme_strlen')) {
  40408. function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); }
  40409. }
  40410. if (!function_exists('grapheme_strpos')) {
  40411. function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); }
  40412. }
  40413. if (!function_exists('grapheme_strripos')) {
  40414. function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); }
  40415. }
  40416. if (!function_exists('grapheme_strrpos')) {
  40417. function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); }
  40418. }
  40419. if (!function_exists('grapheme_strstr')) {
  40420. function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); }
  40421. }
  40422. if (!function_exists('grapheme_substr')) {
  40423. function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); }
  40424. }
  40425. <?php declare(strict_types=1);
  40426. namespace Evenement;
  40427. use InvalidArgumentException;
  40428. use function count;
  40429. use function array_keys;
  40430. use function array_merge;
  40431. use function array_search;
  40432. use function array_unique;
  40433. use function array_values;
  40434. trait EventEmitterTrait
  40435. {
  40436. protected $listeners = [];
  40437. protected $onceListeners = [];
  40438. public function on($event, callable $listener)
  40439. {
  40440. if ($event === null) {
  40441. throw new InvalidArgumentException('event name must not be null');
  40442. }
  40443. if (!isset($this->listeners[$event])) {
  40444. $this->listeners[$event] = [];
  40445. }
  40446. $this->listeners[$event][] = $listener;
  40447. return $this;
  40448. }
  40449. public function once($event, callable $listener)
  40450. {
  40451. if ($event === null) {
  40452. throw new InvalidArgumentException('event name must not be null');
  40453. }
  40454. if (!isset($this->onceListeners[$event])) {
  40455. $this->onceListeners[$event] = [];
  40456. }
  40457. $this->onceListeners[$event][] = $listener;
  40458. return $this;
  40459. }
  40460. public function removeListener($event, callable $listener)
  40461. {
  40462. if ($event === null) {
  40463. throw new InvalidArgumentException('event name must not be null');
  40464. }
  40465. if (isset($this->listeners[$event])) {
  40466. $index = array_search($listener, $this->listeners[$event], true);
  40467. if (false !== $index) {
  40468. unset($this->listeners[$event][$index]);
  40469. if (count($this->listeners[$event]) === 0) {
  40470. unset($this->listeners[$event]);
  40471. }
  40472. }
  40473. }
  40474. if (isset($this->onceListeners[$event])) {
  40475. $index = array_search($listener, $this->onceListeners[$event], true);
  40476. if (false !== $index) {
  40477. unset($this->onceListeners[$event][$index]);
  40478. if (count($this->onceListeners[$event]) === 0) {
  40479. unset($this->onceListeners[$event]);
  40480. }
  40481. }
  40482. }
  40483. }
  40484. public function removeAllListeners($event = null)
  40485. {
  40486. if ($event !== null) {
  40487. unset($this->listeners[$event]);
  40488. } else {
  40489. $this->listeners = [];
  40490. }
  40491. if ($event !== null) {
  40492. unset($this->onceListeners[$event]);
  40493. } else {
  40494. $this->onceListeners = [];
  40495. }
  40496. }
  40497. public function listeners($event = null): array
  40498. {
  40499. if ($event === null) {
  40500. $events = [];
  40501. $eventNames = array_unique(
  40502. array_merge(
  40503. array_keys($this->listeners),
  40504. array_keys($this->onceListeners)
  40505. )
  40506. );
  40507. foreach ($eventNames as $eventName) {
  40508. $events[$eventName] = array_merge(
  40509. isset($this->listeners[$eventName]) ? $this->listeners[$eventName] : [],
  40510. isset($this->onceListeners[$eventName]) ? $this->onceListeners[$eventName] : []
  40511. );
  40512. }
  40513. return $events;
  40514. }
  40515. return array_merge(
  40516. isset($this->listeners[$event]) ? $this->listeners[$event] : [],
  40517. isset($this->onceListeners[$event]) ? $this->onceListeners[$event] : []
  40518. );
  40519. }
  40520. public function emit($event, array $arguments = [])
  40521. {
  40522. if ($event === null) {
  40523. throw new InvalidArgumentException('event name must not be null');
  40524. }
  40525. $listeners = [];
  40526. if (isset($this->listeners[$event])) {
  40527. $listeners = array_values($this->listeners[$event]);
  40528. }
  40529. $onceListeners = [];
  40530. if (isset($this->onceListeners[$event])) {
  40531. $onceListeners = array_values($this->onceListeners[$event]);
  40532. }
  40533. if(empty($listeners) === false) {
  40534. foreach ($listeners as $listener) {
  40535. $listener(...$arguments);
  40536. }
  40537. }
  40538. if(empty($onceListeners) === false) {
  40539. unset($this->onceListeners[$event]);
  40540. foreach ($onceListeners as $listener) {
  40541. $listener(...$arguments);
  40542. }
  40543. }
  40544. }
  40545. }
  40546. <?php declare(strict_types=1);
  40547. namespace Evenement;
  40548. interface EventEmitterInterface
  40549. {
  40550. public function on($event, callable $listener);
  40551. public function once($event, callable $listener);
  40552. public function removeListener($event, callable $listener);
  40553. public function removeAllListeners($event = null);
  40554. public function listeners($event = null);
  40555. public function emit($event, array $arguments = []);
  40556. }
  40557. <?php declare(strict_types=1);
  40558. namespace Evenement;
  40559. class EventEmitter implements EventEmitterInterface
  40560. {
  40561. use EventEmitterTrait;
  40562. }
  40563. <?php
  40564. namespace React\EventLoop;
  40565. final class Factory
  40566. {
  40567. public static function create()
  40568. {
  40569. $loop = self::construct();
  40570. Loop::set($loop);
  40571. return $loop;
  40572. }
  40573. private static function construct()
  40574. {
  40575. if (\function_exists('uv_loop_new')) {
  40576. return new ExtUvLoop();
  40577. }
  40578. if (\class_exists('libev\EventLoop', false)) {
  40579. return new ExtLibevLoop();
  40580. }
  40581. if (\class_exists('EvLoop', false)) {
  40582. return new ExtEvLoop();
  40583. }
  40584. if (\class_exists('EventBase', false)) {
  40585. return new ExtEventLoop();
  40586. }
  40587. if (\function_exists('event_base_new') && \PHP_MAJOR_VERSION === 5) {
  40588. return new ExtLibeventLoop();
  40589. }
  40590. return new StreamSelectLoop();
  40591. }
  40592. }
  40593. <?php
  40594. namespace React\EventLoop;
  40595. use Ev;
  40596. use EvIo;
  40597. use EvLoop;
  40598. use React\EventLoop\Tick\FutureTickQueue;
  40599. use React\EventLoop\Timer\Timer;
  40600. use SplObjectStorage;
  40601. class ExtEvLoop implements LoopInterface
  40602. {
  40603. private $loop;
  40604. private $futureTickQueue;
  40605. private $timers;
  40606. private $readStreams = array();
  40607. private $writeStreams = array();
  40608. private $running;
  40609. private $signals;
  40610. private $signalEvents = array();
  40611. public function __construct()
  40612. {
  40613. $this->loop = new EvLoop();
  40614. $this->futureTickQueue = new FutureTickQueue();
  40615. $this->timers = new SplObjectStorage();
  40616. $this->signals = new SignalsHandler();
  40617. }
  40618. public function addReadStream($stream, $listener)
  40619. {
  40620. $key = (int)$stream;
  40621. if (isset($this->readStreams[$key])) {
  40622. return;
  40623. }
  40624. $callback = $this->getStreamListenerClosure($stream, $listener);
  40625. $event = $this->loop->io($stream, Ev::READ, $callback);
  40626. $this->readStreams[$key] = $event;
  40627. }
  40628. private function getStreamListenerClosure($stream, $listener)
  40629. {
  40630. return function () use ($stream, $listener) {
  40631. \call_user_func($listener, $stream);
  40632. };
  40633. }
  40634. public function addWriteStream($stream, $listener)
  40635. {
  40636. $key = (int)$stream;
  40637. if (isset($this->writeStreams[$key])) {
  40638. return;
  40639. }
  40640. $callback = $this->getStreamListenerClosure($stream, $listener);
  40641. $event = $this->loop->io($stream, Ev::WRITE, $callback);
  40642. $this->writeStreams[$key] = $event;
  40643. }
  40644. public function removeReadStream($stream)
  40645. {
  40646. $key = (int)$stream;
  40647. if (!isset($this->readStreams[$key])) {
  40648. return;
  40649. }
  40650. $this->readStreams[$key]->stop();
  40651. unset($this->readStreams[$key]);
  40652. }
  40653. public function removeWriteStream($stream)
  40654. {
  40655. $key = (int)$stream;
  40656. if (!isset($this->writeStreams[$key])) {
  40657. return;
  40658. }
  40659. $this->writeStreams[$key]->stop();
  40660. unset($this->writeStreams[$key]);
  40661. }
  40662. public function addTimer($interval, $callback)
  40663. {
  40664. $timer = new Timer($interval, $callback, false);
  40665. $that = $this;
  40666. $timers = $this->timers;
  40667. $callback = function () use ($timer, $timers, $that) {
  40668. \call_user_func($timer->getCallback(), $timer);
  40669. if ($timers->contains($timer)) {
  40670. $that->cancelTimer($timer);
  40671. }
  40672. };
  40673. $event = $this->loop->timer($timer->getInterval(), 0.0, $callback);
  40674. $this->timers->attach($timer, $event);
  40675. return $timer;
  40676. }
  40677. public function addPeriodicTimer($interval, $callback)
  40678. {
  40679. $timer = new Timer($interval, $callback, true);
  40680. $callback = function () use ($timer) {
  40681. \call_user_func($timer->getCallback(), $timer);
  40682. };
  40683. $event = $this->loop->timer($timer->getInterval(), $timer->getInterval(), $callback);
  40684. $this->timers->attach($timer, $event);
  40685. return $timer;
  40686. }
  40687. public function cancelTimer(TimerInterface $timer)
  40688. {
  40689. if (!isset($this->timers[$timer])) {
  40690. return;
  40691. }
  40692. $event = $this->timers[$timer];
  40693. $event->stop();
  40694. $this->timers->detach($timer);
  40695. }
  40696. public function futureTick($listener)
  40697. {
  40698. $this->futureTickQueue->add($listener);
  40699. }
  40700. public function run()
  40701. {
  40702. $this->running = true;
  40703. while ($this->running) {
  40704. $this->futureTickQueue->tick();
  40705. $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
  40706. $wasJustStopped = !$this->running;
  40707. $nothingLeftToDo = !$this->readStreams
  40708. && !$this->writeStreams
  40709. && !$this->timers->count()
  40710. && $this->signals->isEmpty();
  40711. $flags = Ev::RUN_ONCE;
  40712. if ($wasJustStopped || $hasPendingCallbacks) {
  40713. $flags |= Ev::RUN_NOWAIT;
  40714. } elseif ($nothingLeftToDo) {
  40715. break;
  40716. }
  40717. $this->loop->run($flags);
  40718. }
  40719. }
  40720. public function stop()
  40721. {
  40722. $this->running = false;
  40723. }
  40724. public function __destruct()
  40725. {
  40726. foreach ($this->timers as $timer) {
  40727. $this->cancelTimer($timer);
  40728. }
  40729. foreach ($this->readStreams as $key => $stream) {
  40730. $this->removeReadStream($key);
  40731. }
  40732. foreach ($this->writeStreams as $key => $stream) {
  40733. $this->removeWriteStream($key);
  40734. }
  40735. }
  40736. public function addSignal($signal, $listener)
  40737. {
  40738. $this->signals->add($signal, $listener);
  40739. if (!isset($this->signalEvents[$signal])) {
  40740. $this->signalEvents[$signal] = $this->loop->signal($signal, function() use ($signal) {
  40741. $this->signals->call($signal);
  40742. });
  40743. }
  40744. }
  40745. public function removeSignal($signal, $listener)
  40746. {
  40747. $this->signals->remove($signal, $listener);
  40748. if (isset($this->signalEvents[$signal])) {
  40749. $this->signalEvents[$signal]->stop();
  40750. unset($this->signalEvents[$signal]);
  40751. }
  40752. }
  40753. }
  40754. <?php
  40755. namespace React\EventLoop;
  40756. use BadMethodCallException;
  40757. use Event;
  40758. use EventBase;
  40759. use React\EventLoop\Tick\FutureTickQueue;
  40760. use React\EventLoop\Timer\Timer;
  40761. use SplObjectStorage;
  40762. final class ExtLibeventLoop implements LoopInterface
  40763. {
  40764. const MICROSECONDS_PER_SECOND = 1000000;
  40765. private $eventBase;
  40766. private $futureTickQueue;
  40767. private $timerCallback;
  40768. private $timerEvents;
  40769. private $streamCallback;
  40770. private $readEvents = array();
  40771. private $writeEvents = array();
  40772. private $readListeners = array();
  40773. private $writeListeners = array();
  40774. private $running;
  40775. private $signals;
  40776. private $signalEvents = array();
  40777. public function __construct()
  40778. {
  40779. if (!\function_exists('event_base_new')) {
  40780. throw new BadMethodCallException('Cannot create ExtLibeventLoop, ext-libevent extension missing');
  40781. }
  40782. $this->eventBase = \event_base_new();
  40783. $this->futureTickQueue = new FutureTickQueue();
  40784. $this->timerEvents = new SplObjectStorage();
  40785. $this->signals = new SignalsHandler();
  40786. $this->createTimerCallback();
  40787. $this->createStreamCallback();
  40788. }
  40789. public function addReadStream($stream, $listener)
  40790. {
  40791. $key = (int) $stream;
  40792. if (isset($this->readListeners[$key])) {
  40793. return;
  40794. }
  40795. $event = \event_new();
  40796. \event_set($event, $stream, \EV_PERSIST | \EV_READ, $this->streamCallback);
  40797. \event_base_set($event, $this->eventBase);
  40798. \event_add($event);
  40799. $this->readEvents[$key] = $event;
  40800. $this->readListeners[$key] = $listener;
  40801. }
  40802. public function addWriteStream($stream, $listener)
  40803. {
  40804. $key = (int) $stream;
  40805. if (isset($this->writeListeners[$key])) {
  40806. return;
  40807. }
  40808. $event = \event_new();
  40809. \event_set($event, $stream, \EV_PERSIST | \EV_WRITE, $this->streamCallback);
  40810. \event_base_set($event, $this->eventBase);
  40811. \event_add($event);
  40812. $this->writeEvents[$key] = $event;
  40813. $this->writeListeners[$key] = $listener;
  40814. }
  40815. public function removeReadStream($stream)
  40816. {
  40817. $key = (int) $stream;
  40818. if (isset($this->readListeners[$key])) {
  40819. $event = $this->readEvents[$key];
  40820. \event_del($event);
  40821. \event_free($event);
  40822. unset(
  40823. $this->readEvents[$key],
  40824. $this->readListeners[$key]
  40825. );
  40826. }
  40827. }
  40828. public function removeWriteStream($stream)
  40829. {
  40830. $key = (int) $stream;
  40831. if (isset($this->writeListeners[$key])) {
  40832. $event = $this->writeEvents[$key];
  40833. \event_del($event);
  40834. \event_free($event);
  40835. unset(
  40836. $this->writeEvents[$key],
  40837. $this->writeListeners[$key]
  40838. );
  40839. }
  40840. }
  40841. public function addTimer($interval, $callback)
  40842. {
  40843. $timer = new Timer($interval, $callback, false);
  40844. $this->scheduleTimer($timer);
  40845. return $timer;
  40846. }
  40847. public function addPeriodicTimer($interval, $callback)
  40848. {
  40849. $timer = new Timer($interval, $callback, true);
  40850. $this->scheduleTimer($timer);
  40851. return $timer;
  40852. }
  40853. public function cancelTimer(TimerInterface $timer)
  40854. {
  40855. if ($this->timerEvents->contains($timer)) {
  40856. $event = $this->timerEvents[$timer];
  40857. \event_del($event);
  40858. \event_free($event);
  40859. $this->timerEvents->detach($timer);
  40860. }
  40861. }
  40862. public function futureTick($listener)
  40863. {
  40864. $this->futureTickQueue->add($listener);
  40865. }
  40866. public function addSignal($signal, $listener)
  40867. {
  40868. $this->signals->add($signal, $listener);
  40869. if (!isset($this->signalEvents[$signal])) {
  40870. $this->signalEvents[$signal] = \event_new();
  40871. \event_set($this->signalEvents[$signal], $signal, \EV_PERSIST | \EV_SIGNAL, array($this->signals, 'call'));
  40872. \event_base_set($this->signalEvents[$signal], $this->eventBase);
  40873. \event_add($this->signalEvents[$signal]);
  40874. }
  40875. }
  40876. public function removeSignal($signal, $listener)
  40877. {
  40878. $this->signals->remove($signal, $listener);
  40879. if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
  40880. \event_del($this->signalEvents[$signal]);
  40881. \event_free($this->signalEvents[$signal]);
  40882. unset($this->signalEvents[$signal]);
  40883. }
  40884. }
  40885. public function run()
  40886. {
  40887. $this->running = true;
  40888. while ($this->running) {
  40889. $this->futureTickQueue->tick();
  40890. $flags = \EVLOOP_ONCE;
  40891. if (!$this->running || !$this->futureTickQueue->isEmpty()) {
  40892. $flags |= \EVLOOP_NONBLOCK;
  40893. } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
  40894. break;
  40895. }
  40896. \event_base_loop($this->eventBase, $flags);
  40897. }
  40898. }
  40899. public function stop()
  40900. {
  40901. $this->running = false;
  40902. }
  40903. private function scheduleTimer(TimerInterface $timer)
  40904. {
  40905. $this->timerEvents[$timer] = $event = \event_timer_new();
  40906. \event_timer_set($event, $this->timerCallback, $timer);
  40907. \event_base_set($event, $this->eventBase);
  40908. \event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND);
  40909. }
  40910. private function createTimerCallback()
  40911. {
  40912. $that = $this;
  40913. $timers = $this->timerEvents;
  40914. $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) {
  40915. \call_user_func($timer->getCallback(), $timer);
  40916. if (!$timers->contains($timer)) {
  40917. return;
  40918. }
  40919. if ($timer->isPeriodic()) {
  40920. \event_add(
  40921. $timers[$timer],
  40922. $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND
  40923. );
  40924. } else {
  40925. $that->cancelTimer($timer);
  40926. }
  40927. };
  40928. }
  40929. private function createStreamCallback()
  40930. {
  40931. $read =& $this->readListeners;
  40932. $write =& $this->writeListeners;
  40933. $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
  40934. $key = (int) $stream;
  40935. if (\EV_READ === (\EV_READ & $flags) && isset($read[$key])) {
  40936. \call_user_func($read[$key], $stream);
  40937. }
  40938. if (\EV_WRITE === (\EV_WRITE & $flags) && isset($write[$key])) {
  40939. \call_user_func($write[$key], $stream);
  40940. }
  40941. };
  40942. }
  40943. }
  40944. <?php
  40945. namespace React\EventLoop\Timer;
  40946. use React\EventLoop\TimerInterface;
  40947. final class Timers
  40948. {
  40949. private $time;
  40950. private $timers = array();
  40951. private $schedule = array();
  40952. private $sorted = true;
  40953. private $useHighResolution;
  40954. public function __construct()
  40955. {
  40956. $this->useHighResolution = \function_exists('hrtime');
  40957. }
  40958. public function updateTime()
  40959. {
  40960. return $this->time = $this->useHighResolution ? \hrtime(true) * 1e-9 : \microtime(true);
  40961. }
  40962. public function getTime()
  40963. {
  40964. return $this->time ?: $this->updateTime();
  40965. }
  40966. public function add(TimerInterface $timer)
  40967. {
  40968. $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
  40969. $this->timers[$id] = $timer;
  40970. $this->schedule[$id] = $timer->getInterval() + $this->updateTime();
  40971. $this->sorted = false;
  40972. }
  40973. public function contains(TimerInterface $timer)
  40974. {
  40975. $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
  40976. return isset($this->timers[$id]);
  40977. }
  40978. public function cancel(TimerInterface $timer)
  40979. {
  40980. $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
  40981. unset($this->timers[$id], $this->schedule[$id]);
  40982. }
  40983. public function getFirst()
  40984. {
  40985. if (!$this->sorted) {
  40986. $this->sorted = true;
  40987. \asort($this->schedule);
  40988. }
  40989. return \reset($this->schedule);
  40990. }
  40991. public function isEmpty()
  40992. {
  40993. return \count($this->timers) === 0;
  40994. }
  40995. public function tick()
  40996. {
  40997. if (!$this->schedule) {
  40998. return;
  40999. }
  41000. if (!$this->sorted) {
  41001. $this->sorted = true;
  41002. \asort($this->schedule);
  41003. }
  41004. $time = $this->updateTime();
  41005. foreach ($this->schedule as $id => $scheduled) {
  41006. if ($scheduled >= $time) {
  41007. break;
  41008. }
  41009. if (!isset($this->schedule[$id]) || $this->schedule[$id] !== $scheduled) {
  41010. continue;
  41011. }
  41012. $timer = $this->timers[$id];
  41013. \call_user_func($timer->getCallback(), $timer);
  41014. if ($timer->isPeriodic() && isset($this->timers[$id])) {
  41015. $this->schedule[$id] = $timer->getInterval() + $time;
  41016. $this->sorted = false;
  41017. } else {
  41018. unset($this->timers[$id], $this->schedule[$id]);
  41019. }
  41020. }
  41021. }
  41022. }
  41023. <?php
  41024. namespace React\EventLoop\Timer;
  41025. use React\EventLoop\TimerInterface;
  41026. final class Timer implements TimerInterface
  41027. {
  41028. const MIN_INTERVAL = 0.000001;
  41029. private $interval;
  41030. private $callback;
  41031. private $periodic;
  41032. public function __construct($interval, $callback, $periodic = false)
  41033. {
  41034. if ($interval < self::MIN_INTERVAL) {
  41035. $interval = self::MIN_INTERVAL;
  41036. }
  41037. $this->interval = (float) $interval;
  41038. $this->callback = $callback;
  41039. $this->periodic = (bool) $periodic;
  41040. }
  41041. public function getInterval()
  41042. {
  41043. return $this->interval;
  41044. }
  41045. public function getCallback()
  41046. {
  41047. return $this->callback;
  41048. }
  41049. public function isPeriodic()
  41050. {
  41051. return $this->periodic;
  41052. }
  41053. }
  41054. <?php
  41055. namespace React\EventLoop;
  41056. final class SignalsHandler
  41057. {
  41058. private $signals = array();
  41059. public function add($signal, $listener)
  41060. {
  41061. if (!isset($this->signals[$signal])) {
  41062. $this->signals[$signal] = array();
  41063. }
  41064. if (\in_array($listener, $this->signals[$signal])) {
  41065. return;
  41066. }
  41067. $this->signals[$signal][] = $listener;
  41068. }
  41069. public function remove($signal, $listener)
  41070. {
  41071. if (!isset($this->signals[$signal])) {
  41072. return;
  41073. }
  41074. $index = \array_search($listener, $this->signals[$signal], true);
  41075. unset($this->signals[$signal][$index]);
  41076. if (isset($this->signals[$signal]) && \count($this->signals[$signal]) === 0) {
  41077. unset($this->signals[$signal]);
  41078. }
  41079. }
  41080. public function call($signal)
  41081. {
  41082. if (!isset($this->signals[$signal])) {
  41083. return;
  41084. }
  41085. foreach ($this->signals[$signal] as $listener) {
  41086. \call_user_func($listener, $signal);
  41087. }
  41088. }
  41089. public function count($signal)
  41090. {
  41091. if (!isset($this->signals[$signal])) {
  41092. return 0;
  41093. }
  41094. return \count($this->signals[$signal]);
  41095. }
  41096. public function isEmpty()
  41097. {
  41098. return !$this->signals;
  41099. }
  41100. }
  41101. <?php
  41102. namespace React\EventLoop;
  41103. use React\EventLoop\Tick\FutureTickQueue;
  41104. use React\EventLoop\Timer\Timer;
  41105. use React\EventLoop\Timer\Timers;
  41106. final class StreamSelectLoop implements LoopInterface
  41107. {
  41108. const MICROSECONDS_PER_SECOND = 1000000;
  41109. private $futureTickQueue;
  41110. private $timers;
  41111. private $readStreams = array();
  41112. private $readListeners = array();
  41113. private $writeStreams = array();
  41114. private $writeListeners = array();
  41115. private $running;
  41116. private $pcntl = false;
  41117. private $pcntlPoll = false;
  41118. private $signals;
  41119. public function __construct()
  41120. {
  41121. $this->futureTickQueue = new FutureTickQueue();
  41122. $this->timers = new Timers();
  41123. $this->pcntl = \function_exists('pcntl_signal') && \function_exists('pcntl_signal_dispatch');
  41124. $this->pcntlPoll = $this->pcntl && !\function_exists('pcntl_async_signals');
  41125. $this->signals = new SignalsHandler();
  41126. if ($this->pcntl && !$this->pcntlPoll) {
  41127. \pcntl_async_signals(true);
  41128. }
  41129. }
  41130. public function addReadStream($stream, $listener)
  41131. {
  41132. $key = (int) $stream;
  41133. if (!isset($this->readStreams[$key])) {
  41134. $this->readStreams[$key] = $stream;
  41135. $this->readListeners[$key] = $listener;
  41136. }
  41137. }
  41138. public function addWriteStream($stream, $listener)
  41139. {
  41140. $key = (int) $stream;
  41141. if (!isset($this->writeStreams[$key])) {
  41142. $this->writeStreams[$key] = $stream;
  41143. $this->writeListeners[$key] = $listener;
  41144. }
  41145. }
  41146. public function removeReadStream($stream)
  41147. {
  41148. $key = (int) $stream;
  41149. unset(
  41150. $this->readStreams[$key],
  41151. $this->readListeners[$key]
  41152. );
  41153. }
  41154. public function removeWriteStream($stream)
  41155. {
  41156. $key = (int) $stream;
  41157. unset(
  41158. $this->writeStreams[$key],
  41159. $this->writeListeners[$key]
  41160. );
  41161. }
  41162. public function addTimer($interval, $callback)
  41163. {
  41164. $timer = new Timer($interval, $callback, false);
  41165. $this->timers->add($timer);
  41166. return $timer;
  41167. }
  41168. public function addPeriodicTimer($interval, $callback)
  41169. {
  41170. $timer = new Timer($interval, $callback, true);
  41171. $this->timers->add($timer);
  41172. return $timer;
  41173. }
  41174. public function cancelTimer(TimerInterface $timer)
  41175. {
  41176. $this->timers->cancel($timer);
  41177. }
  41178. public function futureTick($listener)
  41179. {
  41180. $this->futureTickQueue->add($listener);
  41181. }
  41182. public function addSignal($signal, $listener)
  41183. {
  41184. if ($this->pcntl === false) {
  41185. throw new \BadMethodCallException('Event loop feature "signals" isn\'t supported by the "StreamSelectLoop"');
  41186. }
  41187. $first = $this->signals->count($signal) === 0;
  41188. $this->signals->add($signal, $listener);
  41189. if ($first) {
  41190. \pcntl_signal($signal, array($this->signals, 'call'));
  41191. }
  41192. }
  41193. public function removeSignal($signal, $listener)
  41194. {
  41195. if (!$this->signals->count($signal)) {
  41196. return;
  41197. }
  41198. $this->signals->remove($signal, $listener);
  41199. if ($this->signals->count($signal) === 0) {
  41200. \pcntl_signal($signal, \SIG_DFL);
  41201. }
  41202. }
  41203. public function run()
  41204. {
  41205. $this->running = true;
  41206. while ($this->running) {
  41207. $this->futureTickQueue->tick();
  41208. $this->timers->tick();
  41209. if (!$this->running || !$this->futureTickQueue->isEmpty()) {
  41210. $timeout = 0;
  41211. } elseif ($scheduledAt = $this->timers->getFirst()) {
  41212. $timeout = $scheduledAt - $this->timers->getTime();
  41213. if ($timeout < 0) {
  41214. $timeout = 0;
  41215. } else {
  41216. $timeout *= self::MICROSECONDS_PER_SECOND;
  41217. $timeout = $timeout > \PHP_INT_MAX ? \PHP_INT_MAX : (int)$timeout;
  41218. }
  41219. } elseif ($this->readStreams || $this->writeStreams || !$this->signals->isEmpty()) {
  41220. $timeout = null;
  41221. } else {
  41222. break;
  41223. }
  41224. $this->waitForStreamActivity($timeout);
  41225. }
  41226. }
  41227. public function stop()
  41228. {
  41229. $this->running = false;
  41230. }
  41231. private function waitForStreamActivity($timeout)
  41232. {
  41233. $read = $this->readStreams;
  41234. $write = $this->writeStreams;
  41235. $available = $this->streamSelect($read, $write, $timeout);
  41236. if ($this->pcntlPoll) {
  41237. \pcntl_signal_dispatch();
  41238. }
  41239. if (false === $available) {
  41240. return;
  41241. }
  41242. foreach ($read as $stream) {
  41243. $key = (int) $stream;
  41244. if (isset($this->readListeners[$key])) {
  41245. \call_user_func($this->readListeners[$key], $stream);
  41246. }
  41247. }
  41248. foreach ($write as $stream) {
  41249. $key = (int) $stream;
  41250. if (isset($this->writeListeners[$key])) {
  41251. \call_user_func($this->writeListeners[$key], $stream);
  41252. }
  41253. }
  41254. }
  41255. private function streamSelect(array &$read, array &$write, $timeout)
  41256. {
  41257. if ($read || $write) {
  41258. $except = null;
  41259. if (\DIRECTORY_SEPARATOR === '\\') {
  41260. $except = array();
  41261. foreach ($write as $key => $socket) {
  41262. if (!isset($read[$key]) && @\ftell($socket) === 0) {
  41263. $except[$key] = $socket;
  41264. }
  41265. }
  41266. }
  41267. $previous = \set_error_handler(function ($errno, $errstr) use (&$previous) {
  41268. $eintr = \defined('SOCKET_EINTR') ? \SOCKET_EINTR : (\defined('PCNTL_EINTR') ? \PCNTL_EINTR : 4);
  41269. if ($errno === \E_WARNING && \strpos($errstr, '[' . $eintr .']: ') !== false) {
  41270. return;
  41271. }
  41272. return ($previous !== null) ? \call_user_func_array($previous, \func_get_args()) : false;
  41273. });
  41274. try {
  41275. $ret = \stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout);
  41276. \restore_error_handler();
  41277. } catch (\Throwable $e) {
  41278. \restore_error_handler();
  41279. throw $e;
  41280. } catch (\Exception $e) {
  41281. \restore_error_handler();
  41282. throw $e;
  41283. }
  41284. if ($except) {
  41285. $write = \array_merge($write, $except);
  41286. }
  41287. return $ret;
  41288. }
  41289. if ($timeout > 0) {
  41290. \usleep($timeout);
  41291. } elseif ($timeout === null) {
  41292. \sleep(PHP_INT_MAX);
  41293. }
  41294. return 0;
  41295. }
  41296. }
  41297. <?php
  41298. namespace React\EventLoop;
  41299. use BadMethodCallException;
  41300. use Event;
  41301. use EventBase;
  41302. use React\EventLoop\Tick\FutureTickQueue;
  41303. use React\EventLoop\Timer\Timer;
  41304. use SplObjectStorage;
  41305. final class ExtEventLoop implements LoopInterface
  41306. {
  41307. private $eventBase;
  41308. private $futureTickQueue;
  41309. private $timerCallback;
  41310. private $timerEvents;
  41311. private $streamCallback;
  41312. private $readEvents = array();
  41313. private $writeEvents = array();
  41314. private $readListeners = array();
  41315. private $writeListeners = array();
  41316. private $readRefs = array();
  41317. private $writeRefs = array();
  41318. private $running;
  41319. private $signals;
  41320. private $signalEvents = array();
  41321. public function __construct()
  41322. {
  41323. if (!\class_exists('EventBase', false)) {
  41324. throw new BadMethodCallException('Cannot create ExtEventLoop, ext-event extension missing');
  41325. }
  41326. $config = new \EventConfig();
  41327. if (\DIRECTORY_SEPARATOR !== '\\') {
  41328. $config->requireFeatures(\EventConfig::FEATURE_FDS);
  41329. }
  41330. $this->eventBase = new EventBase($config);
  41331. $this->futureTickQueue = new FutureTickQueue();
  41332. $this->timerEvents = new SplObjectStorage();
  41333. $this->signals = new SignalsHandler();
  41334. $this->createTimerCallback();
  41335. $this->createStreamCallback();
  41336. }
  41337. public function __destruct()
  41338. {
  41339. foreach ($this->timerEvents as $timer) {
  41340. $this->timerEvents->detach($timer);
  41341. }
  41342. $this->readEvents = array();
  41343. $this->writeEvents = array();
  41344. }
  41345. public function addReadStream($stream, $listener)
  41346. {
  41347. $key = (int) $stream;
  41348. if (isset($this->readListeners[$key])) {
  41349. return;
  41350. }
  41351. $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::READ, $this->streamCallback);
  41352. $event->add();
  41353. $this->readEvents[$key] = $event;
  41354. $this->readListeners[$key] = $listener;
  41355. if (\PHP_VERSION_ID >= 70000) {
  41356. $this->readRefs[$key] = $stream;
  41357. }
  41358. }
  41359. public function addWriteStream($stream, $listener)
  41360. {
  41361. $key = (int) $stream;
  41362. if (isset($this->writeListeners[$key])) {
  41363. return;
  41364. }
  41365. $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::WRITE, $this->streamCallback);
  41366. $event->add();
  41367. $this->writeEvents[$key] = $event;
  41368. $this->writeListeners[$key] = $listener;
  41369. if (\PHP_VERSION_ID >= 70000) {
  41370. $this->writeRefs[$key] = $stream;
  41371. }
  41372. }
  41373. public function removeReadStream($stream)
  41374. {
  41375. $key = (int) $stream;
  41376. if (isset($this->readEvents[$key])) {
  41377. $this->readEvents[$key]->free();
  41378. unset(
  41379. $this->readEvents[$key],
  41380. $this->readListeners[$key],
  41381. $this->readRefs[$key]
  41382. );
  41383. }
  41384. }
  41385. public function removeWriteStream($stream)
  41386. {
  41387. $key = (int) $stream;
  41388. if (isset($this->writeEvents[$key])) {
  41389. $this->writeEvents[$key]->free();
  41390. unset(
  41391. $this->writeEvents[$key],
  41392. $this->writeListeners[$key],
  41393. $this->writeRefs[$key]
  41394. );
  41395. }
  41396. }
  41397. public function addTimer($interval, $callback)
  41398. {
  41399. $timer = new Timer($interval, $callback, false);
  41400. $this->scheduleTimer($timer);
  41401. return $timer;
  41402. }
  41403. public function addPeriodicTimer($interval, $callback)
  41404. {
  41405. $timer = new Timer($interval, $callback, true);
  41406. $this->scheduleTimer($timer);
  41407. return $timer;
  41408. }
  41409. public function cancelTimer(TimerInterface $timer)
  41410. {
  41411. if ($this->timerEvents->contains($timer)) {
  41412. $this->timerEvents[$timer]->free();
  41413. $this->timerEvents->detach($timer);
  41414. }
  41415. }
  41416. public function futureTick($listener)
  41417. {
  41418. $this->futureTickQueue->add($listener);
  41419. }
  41420. public function addSignal($signal, $listener)
  41421. {
  41422. $this->signals->add($signal, $listener);
  41423. if (!isset($this->signalEvents[$signal])) {
  41424. $this->signalEvents[$signal] = Event::signal($this->eventBase, $signal, array($this->signals, 'call'));
  41425. $this->signalEvents[$signal]->add();
  41426. }
  41427. }
  41428. public function removeSignal($signal, $listener)
  41429. {
  41430. $this->signals->remove($signal, $listener);
  41431. if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
  41432. $this->signalEvents[$signal]->free();
  41433. unset($this->signalEvents[$signal]);
  41434. }
  41435. }
  41436. public function run()
  41437. {
  41438. $this->running = true;
  41439. while ($this->running) {
  41440. $this->futureTickQueue->tick();
  41441. $flags = EventBase::LOOP_ONCE;
  41442. if (!$this->running || !$this->futureTickQueue->isEmpty()) {
  41443. $flags |= EventBase::LOOP_NONBLOCK;
  41444. } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
  41445. break;
  41446. }
  41447. $this->eventBase->loop($flags);
  41448. }
  41449. }
  41450. public function stop()
  41451. {
  41452. $this->running = false;
  41453. }
  41454. private function scheduleTimer(TimerInterface $timer)
  41455. {
  41456. $flags = Event::TIMEOUT;
  41457. if ($timer->isPeriodic()) {
  41458. $flags |= Event::PERSIST;
  41459. }
  41460. $event = new Event($this->eventBase, -1, $flags, $this->timerCallback, $timer);
  41461. $this->timerEvents[$timer] = $event;
  41462. $event->add($timer->getInterval());
  41463. }
  41464. private function createTimerCallback()
  41465. {
  41466. $timers = $this->timerEvents;
  41467. $this->timerCallback = function ($_, $__, $timer) use ($timers) {
  41468. \call_user_func($timer->getCallback(), $timer);
  41469. if (!$timer->isPeriodic() && $timers->contains($timer)) {
  41470. $this->cancelTimer($timer);
  41471. }
  41472. };
  41473. }
  41474. private function createStreamCallback()
  41475. {
  41476. $read =& $this->readListeners;
  41477. $write =& $this->writeListeners;
  41478. $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
  41479. $key = (int) $stream;
  41480. if (Event::READ === (Event::READ & $flags) && isset($read[$key])) {
  41481. \call_user_func($read[$key], $stream);
  41482. }
  41483. if (Event::WRITE === (Event::WRITE & $flags) && isset($write[$key])) {
  41484. \call_user_func($write[$key], $stream);
  41485. }
  41486. };
  41487. }
  41488. }
  41489. <?php
  41490. namespace React\EventLoop;
  41491. interface TimerInterface
  41492. {
  41493. public function getInterval();
  41494. public function getCallback();
  41495. public function isPeriodic();
  41496. }
  41497. <?php
  41498. namespace React\EventLoop;
  41499. interface LoopInterface
  41500. {
  41501. public function addReadStream($stream, $listener);
  41502. public function addWriteStream($stream, $listener);
  41503. public function removeReadStream($stream);
  41504. public function removeWriteStream($stream);
  41505. public function addTimer($interval, $callback);
  41506. public function addPeriodicTimer($interval, $callback);
  41507. public function cancelTimer(TimerInterface $timer);
  41508. public function futureTick($listener);
  41509. public function addSignal($signal, $listener);
  41510. public function removeSignal($signal, $listener);
  41511. public function run();
  41512. public function stop();
  41513. }
  41514. <?php
  41515. namespace React\EventLoop;
  41516. final class Loop
  41517. {
  41518. private static $instance;
  41519. private static $stopped = false;
  41520. public static function get()
  41521. {
  41522. if (self::$instance instanceof LoopInterface) {
  41523. return self::$instance;
  41524. }
  41525. self::$instance = $loop = Factory::create();
  41526. $hasRun = false;
  41527. $loop->futureTick(function () use (&$hasRun) {
  41528. $hasRun = true;
  41529. });
  41530. $stopped =& self::$stopped;
  41531. register_shutdown_function(function () use ($loop, &$hasRun, &$stopped) {
  41532. $error = error_get_last();
  41533. if ((isset($error['type']) ? $error['type'] : 0) & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
  41534. return;
  41535. }
  41536. if (!$hasRun && !$stopped) {
  41537. $loop->run();
  41538. }
  41539. });
  41540. return self::$instance;
  41541. }
  41542. public static function set(LoopInterface $loop)
  41543. {
  41544. self::$instance = $loop;
  41545. }
  41546. public static function addReadStream($stream, $listener)
  41547. {
  41548. if (self::$instance === null) {
  41549. self::get();
  41550. }
  41551. self::$instance->addReadStream($stream, $listener);
  41552. }
  41553. public static function addWriteStream($stream, $listener)
  41554. {
  41555. if (self::$instance === null) {
  41556. self::get();
  41557. }
  41558. self::$instance->addWriteStream($stream, $listener);
  41559. }
  41560. public static function removeReadStream($stream)
  41561. {
  41562. if (self::$instance !== null) {
  41563. self::$instance->removeReadStream($stream);
  41564. }
  41565. }
  41566. public static function removeWriteStream($stream)
  41567. {
  41568. if (self::$instance !== null) {
  41569. self::$instance->removeWriteStream($stream);
  41570. }
  41571. }
  41572. public static function addTimer($interval, $callback)
  41573. {
  41574. if (self::$instance === null) {
  41575. self::get();
  41576. }
  41577. return self::$instance->addTimer($interval, $callback);
  41578. }
  41579. public static function addPeriodicTimer($interval, $callback)
  41580. {
  41581. if (self::$instance === null) {
  41582. self::get();
  41583. }
  41584. return self::$instance->addPeriodicTimer($interval, $callback);
  41585. }
  41586. public static function cancelTimer(TimerInterface $timer)
  41587. {
  41588. if (self::$instance !== null) {
  41589. self::$instance->cancelTimer($timer);
  41590. }
  41591. }
  41592. public static function futureTick($listener)
  41593. {
  41594. if (self::$instance === null) {
  41595. self::get();
  41596. }
  41597. self::$instance->futureTick($listener);
  41598. }
  41599. public static function addSignal($signal, $listener)
  41600. {
  41601. if (self::$instance === null) {
  41602. self::get();
  41603. }
  41604. self::$instance->addSignal($signal, $listener);
  41605. }
  41606. public static function removeSignal($signal, $listener)
  41607. {
  41608. if (self::$instance !== null) {
  41609. self::$instance->removeSignal($signal, $listener);
  41610. }
  41611. }
  41612. public static function run()
  41613. {
  41614. if (self::$instance === null) {
  41615. self::get();
  41616. }
  41617. self::$instance->run();
  41618. }
  41619. public static function stop()
  41620. {
  41621. self::$stopped = true;
  41622. if (self::$instance !== null) {
  41623. self::$instance->stop();
  41624. }
  41625. }
  41626. }
  41627. <?php
  41628. namespace React\EventLoop;
  41629. use React\EventLoop\Tick\FutureTickQueue;
  41630. use React\EventLoop\Timer\Timer;
  41631. use SplObjectStorage;
  41632. final class ExtUvLoop implements LoopInterface
  41633. {
  41634. private $uv;
  41635. private $futureTickQueue;
  41636. private $timers;
  41637. private $streamEvents = array();
  41638. private $readStreams = array();
  41639. private $writeStreams = array();
  41640. private $running;
  41641. private $signals;
  41642. private $signalEvents = array();
  41643. private $streamListener;
  41644. public function __construct()
  41645. {
  41646. if (!\function_exists('uv_loop_new')) {
  41647. throw new \BadMethodCallException('Cannot create LibUvLoop, ext-uv extension missing');
  41648. }
  41649. $this->uv = \uv_loop_new();
  41650. $this->futureTickQueue = new FutureTickQueue();
  41651. $this->timers = new SplObjectStorage();
  41652. $this->streamListener = $this->createStreamListener();
  41653. $this->signals = new SignalsHandler();
  41654. }
  41655. public function getUvLoop()
  41656. {
  41657. return $this->uv;
  41658. }
  41659. public function addReadStream($stream, $listener)
  41660. {
  41661. if (isset($this->readStreams[(int) $stream])) {
  41662. return;
  41663. }
  41664. $this->readStreams[(int) $stream] = $listener;
  41665. $this->addStream($stream);
  41666. }
  41667. public function addWriteStream($stream, $listener)
  41668. {
  41669. if (isset($this->writeStreams[(int) $stream])) {
  41670. return;
  41671. }
  41672. $this->writeStreams[(int) $stream] = $listener;
  41673. $this->addStream($stream);
  41674. }
  41675. public function removeReadStream($stream)
  41676. {
  41677. if (!isset($this->streamEvents[(int) $stream])) {
  41678. return;
  41679. }
  41680. unset($this->readStreams[(int) $stream]);
  41681. $this->removeStream($stream);
  41682. }
  41683. public function removeWriteStream($stream)
  41684. {
  41685. if (!isset($this->streamEvents[(int) $stream])) {
  41686. return;
  41687. }
  41688. unset($this->writeStreams[(int) $stream]);
  41689. $this->removeStream($stream);
  41690. }
  41691. public function addTimer($interval, $callback)
  41692. {
  41693. $timer = new Timer($interval, $callback, false);
  41694. $that = $this;
  41695. $timers = $this->timers;
  41696. $callback = function () use ($timer, $timers, $that) {
  41697. \call_user_func($timer->getCallback(), $timer);
  41698. if ($timers->contains($timer)) {
  41699. $that->cancelTimer($timer);
  41700. }
  41701. };
  41702. $event = \uv_timer_init($this->uv);
  41703. $this->timers->attach($timer, $event);
  41704. \uv_timer_start(
  41705. $event,
  41706. $this->convertFloatSecondsToMilliseconds($interval),
  41707. 0,
  41708. $callback
  41709. );
  41710. return $timer;
  41711. }
  41712. public function addPeriodicTimer($interval, $callback)
  41713. {
  41714. $timer = new Timer($interval, $callback, true);
  41715. $callback = function () use ($timer) {
  41716. \call_user_func($timer->getCallback(), $timer);
  41717. };
  41718. $interval = $this->convertFloatSecondsToMilliseconds($interval);
  41719. $event = \uv_timer_init($this->uv);
  41720. $this->timers->attach($timer, $event);
  41721. \uv_timer_start(
  41722. $event,
  41723. $interval,
  41724. (int) $interval === 0 ? 1 : $interval,
  41725. $callback
  41726. );
  41727. return $timer;
  41728. }
  41729. public function cancelTimer(TimerInterface $timer)
  41730. {
  41731. if (isset($this->timers[$timer])) {
  41732. @\uv_timer_stop($this->timers[$timer]);
  41733. $this->timers->detach($timer);
  41734. }
  41735. }
  41736. public function futureTick($listener)
  41737. {
  41738. $this->futureTickQueue->add($listener);
  41739. }
  41740. public function addSignal($signal, $listener)
  41741. {
  41742. $this->signals->add($signal, $listener);
  41743. if (!isset($this->signalEvents[$signal])) {
  41744. $signals = $this->signals;
  41745. $this->signalEvents[$signal] = \uv_signal_init($this->uv);
  41746. \uv_signal_start($this->signalEvents[$signal], function () use ($signals, $signal) {
  41747. $signals->call($signal);
  41748. }, $signal);
  41749. }
  41750. }
  41751. public function removeSignal($signal, $listener)
  41752. {
  41753. $this->signals->remove($signal, $listener);
  41754. if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
  41755. \uv_signal_stop($this->signalEvents[$signal]);
  41756. unset($this->signalEvents[$signal]);
  41757. }
  41758. }
  41759. public function run()
  41760. {
  41761. $this->running = true;
  41762. while ($this->running) {
  41763. $this->futureTickQueue->tick();
  41764. $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
  41765. $wasJustStopped = !$this->running;
  41766. $nothingLeftToDo = !$this->readStreams
  41767. && !$this->writeStreams
  41768. && !$this->timers->count()
  41769. && $this->signals->isEmpty();
  41770. $flags = \UV::RUN_ONCE;
  41771. if ($wasJustStopped || $hasPendingCallbacks) {
  41772. $flags = \UV::RUN_NOWAIT;
  41773. } elseif ($nothingLeftToDo) {
  41774. break;
  41775. }
  41776. \uv_run($this->uv, $flags);
  41777. }
  41778. }
  41779. public function stop()
  41780. {
  41781. $this->running = false;
  41782. }
  41783. private function addStream($stream)
  41784. {
  41785. if (!isset($this->streamEvents[(int) $stream])) {
  41786. $this->streamEvents[(int)$stream] = \uv_poll_init_socket($this->uv, $stream);
  41787. }
  41788. if ($this->streamEvents[(int) $stream] !== false) {
  41789. $this->pollStream($stream);
  41790. }
  41791. }
  41792. private function removeStream($stream)
  41793. {
  41794. if (!isset($this->streamEvents[(int) $stream])) {
  41795. return;
  41796. }
  41797. if (!isset($this->readStreams[(int) $stream])
  41798. && !isset($this->writeStreams[(int) $stream])) {
  41799. \uv_poll_stop($this->streamEvents[(int) $stream]);
  41800. \uv_close($this->streamEvents[(int) $stream]);
  41801. unset($this->streamEvents[(int) $stream]);
  41802. return;
  41803. }
  41804. $this->pollStream($stream);
  41805. }
  41806. private function pollStream($stream)
  41807. {
  41808. if (!isset($this->streamEvents[(int) $stream])) {
  41809. return;
  41810. }
  41811. $flags = 0;
  41812. if (isset($this->readStreams[(int) $stream])) {
  41813. $flags |= \UV::READABLE;
  41814. }
  41815. if (isset($this->writeStreams[(int) $stream])) {
  41816. $flags |= \UV::WRITABLE;
  41817. }
  41818. \uv_poll_start($this->streamEvents[(int) $stream], $flags, $this->streamListener);
  41819. }
  41820. private function createStreamListener()
  41821. {
  41822. $callback = function ($event, $status, $events, $stream) {
  41823. if ($status !== 0) {
  41824. $this->pollStream($stream);
  41825. if ($events === 0) {
  41826. $events = \UV::READABLE | \UV::WRITABLE;
  41827. }
  41828. }
  41829. if (isset($this->readStreams[(int) $stream]) && ($events & \UV::READABLE)) {
  41830. \call_user_func($this->readStreams[(int) $stream], $stream);
  41831. }
  41832. if (isset($this->writeStreams[(int) $stream]) && ($events & \UV::WRITABLE)) {
  41833. \call_user_func($this->writeStreams[(int) $stream], $stream);
  41834. }
  41835. };
  41836. return $callback;
  41837. }
  41838. private function convertFloatSecondsToMilliseconds($interval)
  41839. {
  41840. if ($interval < 0) {
  41841. return 0;
  41842. }
  41843. $maxValue = (int) (\PHP_INT_MAX / 1000);
  41844. $intInterval = (int) $interval;
  41845. if (($intInterval <= 0 && $interval > 1) || $intInterval >= $maxValue) {
  41846. throw new \InvalidArgumentException(
  41847. "Interval overflow, value must be lower than '{$maxValue}', but '{$interval}' passed."
  41848. );
  41849. }
  41850. return (int) \floor($interval * 1000);
  41851. }
  41852. }
  41853. <?php
  41854. namespace React\EventLoop;
  41855. use BadMethodCallException;
  41856. use libev\EventLoop;
  41857. use libev\IOEvent;
  41858. use libev\SignalEvent;
  41859. use libev\TimerEvent;
  41860. use React\EventLoop\Tick\FutureTickQueue;
  41861. use React\EventLoop\Timer\Timer;
  41862. use SplObjectStorage;
  41863. final class ExtLibevLoop implements LoopInterface
  41864. {
  41865. private $loop;
  41866. private $futureTickQueue;
  41867. private $timerEvents;
  41868. private $readEvents = array();
  41869. private $writeEvents = array();
  41870. private $running;
  41871. private $signals;
  41872. private $signalEvents = array();
  41873. public function __construct()
  41874. {
  41875. if (!\class_exists('libev\EventLoop', false)) {
  41876. throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing');
  41877. }
  41878. $this->loop = new EventLoop();
  41879. $this->futureTickQueue = new FutureTickQueue();
  41880. $this->timerEvents = new SplObjectStorage();
  41881. $this->signals = new SignalsHandler();
  41882. }
  41883. public function addReadStream($stream, $listener)
  41884. {
  41885. if (isset($this->readEvents[(int) $stream])) {
  41886. return;
  41887. }
  41888. $callback = function () use ($stream, $listener) {
  41889. \call_user_func($listener, $stream);
  41890. };
  41891. $event = new IOEvent($callback, $stream, IOEvent::READ);
  41892. $this->loop->add($event);
  41893. $this->readEvents[(int) $stream] = $event;
  41894. }
  41895. public function addWriteStream($stream, $listener)
  41896. {
  41897. if (isset($this->writeEvents[(int) $stream])) {
  41898. return;
  41899. }
  41900. $callback = function () use ($stream, $listener) {
  41901. \call_user_func($listener, $stream);
  41902. };
  41903. $event = new IOEvent($callback, $stream, IOEvent::WRITE);
  41904. $this->loop->add($event);
  41905. $this->writeEvents[(int) $stream] = $event;
  41906. }
  41907. public function removeReadStream($stream)
  41908. {
  41909. $key = (int) $stream;
  41910. if (isset($this->readEvents[$key])) {
  41911. $this->readEvents[$key]->stop();
  41912. $this->loop->remove($this->readEvents[$key]);
  41913. unset($this->readEvents[$key]);
  41914. }
  41915. }
  41916. public function removeWriteStream($stream)
  41917. {
  41918. $key = (int) $stream;
  41919. if (isset($this->writeEvents[$key])) {
  41920. $this->writeEvents[$key]->stop();
  41921. $this->loop->remove($this->writeEvents[$key]);
  41922. unset($this->writeEvents[$key]);
  41923. }
  41924. }
  41925. public function addTimer($interval, $callback)
  41926. {
  41927. $timer = new Timer( $interval, $callback, false);
  41928. $that = $this;
  41929. $timers = $this->timerEvents;
  41930. $callback = function () use ($timer, $timers, $that) {
  41931. \call_user_func($timer->getCallback(), $timer);
  41932. if ($timers->contains($timer)) {
  41933. $that->cancelTimer($timer);
  41934. }
  41935. };
  41936. $event = new TimerEvent($callback, $timer->getInterval());
  41937. $this->timerEvents->attach($timer, $event);
  41938. $this->loop->add($event);
  41939. return $timer;
  41940. }
  41941. public function addPeriodicTimer($interval, $callback)
  41942. {
  41943. $timer = new Timer($interval, $callback, true);
  41944. $callback = function () use ($timer) {
  41945. \call_user_func($timer->getCallback(), $timer);
  41946. };
  41947. $event = new TimerEvent($callback, $timer->getInterval(), $timer->getInterval());
  41948. $this->timerEvents->attach($timer, $event);
  41949. $this->loop->add($event);
  41950. return $timer;
  41951. }
  41952. public function cancelTimer(TimerInterface $timer)
  41953. {
  41954. if (isset($this->timerEvents[$timer])) {
  41955. $this->loop->remove($this->timerEvents[$timer]);
  41956. $this->timerEvents->detach($timer);
  41957. }
  41958. }
  41959. public function futureTick($listener)
  41960. {
  41961. $this->futureTickQueue->add($listener);
  41962. }
  41963. public function addSignal($signal, $listener)
  41964. {
  41965. $this->signals->add($signal, $listener);
  41966. if (!isset($this->signalEvents[$signal])) {
  41967. $signals = $this->signals;
  41968. $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) {
  41969. $signals->call($signal);
  41970. }, $signal);
  41971. $this->loop->add($this->signalEvents[$signal]);
  41972. }
  41973. }
  41974. public function removeSignal($signal, $listener)
  41975. {
  41976. $this->signals->remove($signal, $listener);
  41977. if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
  41978. $this->signalEvents[$signal]->stop();
  41979. $this->loop->remove($this->signalEvents[$signal]);
  41980. unset($this->signalEvents[$signal]);
  41981. }
  41982. }
  41983. public function run()
  41984. {
  41985. $this->running = true;
  41986. while ($this->running) {
  41987. $this->futureTickQueue->tick();
  41988. $flags = EventLoop::RUN_ONCE;
  41989. if (!$this->running || !$this->futureTickQueue->isEmpty()) {
  41990. $flags |= EventLoop::RUN_NOWAIT;
  41991. } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
  41992. break;
  41993. }
  41994. $this->loop->run($flags);
  41995. }
  41996. }
  41997. public function stop()
  41998. {
  41999. $this->running = false;
  42000. }
  42001. }
  42002. <?php
  42003. namespace React\EventLoop\Tick;
  42004. use SplQueue;
  42005. final class FutureTickQueue
  42006. {
  42007. private $queue;
  42008. public function __construct()
  42009. {
  42010. $this->queue = new SplQueue();
  42011. }
  42012. public function add($listener)
  42013. {
  42014. $this->queue->enqueue($listener);
  42015. }
  42016. public function tick()
  42017. {
  42018. $count = $this->queue->count();
  42019. while ($count--) {
  42020. \call_user_func(
  42021. $this->queue->dequeue()
  42022. );
  42023. }
  42024. }
  42025. public function isEmpty()
  42026. {
  42027. return $this->queue->isEmpty();
  42028. }
  42029. }
  42030. <?php
  42031. namespace React\Cache;
  42032. use React\Promise\PromiseInterface;
  42033. interface CacheInterface
  42034. {
  42035. public function get($key, $default = null);
  42036. public function set($key, $value, $ttl = null);
  42037. public function delete($key);
  42038. public function getMultiple(array $keys, $default = null);
  42039. public function setMultiple(array $values, $ttl = null);
  42040. public function deleteMultiple(array $keys);
  42041. public function clear();
  42042. public function has($key);
  42043. }
  42044. <?php
  42045. namespace React\Cache;
  42046. use React\Promise;
  42047. use React\Promise\PromiseInterface;
  42048. class ArrayCache implements CacheInterface
  42049. {
  42050. private $limit;
  42051. private $data = array();
  42052. private $expires = array();
  42053. private $supportsHighResolution;
  42054. public function __construct($limit = null)
  42055. {
  42056. $this->limit = $limit;
  42057. $this->supportsHighResolution = \function_exists('hrtime');
  42058. }
  42059. public function get($key, $default = null)
  42060. {
  42061. if (isset($this->expires[$key]) && $this->now() - $this->expires[$key] > 0) {
  42062. unset($this->data[$key], $this->expires[$key]);
  42063. }
  42064. if (!\array_key_exists($key, $this->data)) {
  42065. return Promise\resolve($default);
  42066. }
  42067. $value = $this->data[$key];
  42068. unset($this->data[$key]);
  42069. $this->data[$key] = $value;
  42070. return Promise\resolve($value);
  42071. }
  42072. public function set($key, $value, $ttl = null)
  42073. {
  42074. unset($this->data[$key]);
  42075. $this->data[$key] = $value;
  42076. unset($this->expires[$key]);
  42077. if ($ttl !== null) {
  42078. $this->expires[$key] = $this->now() + $ttl;
  42079. \asort($this->expires);
  42080. }
  42081. if ($this->limit !== null && \count($this->data) > $this->limit) {
  42082. \reset($this->expires);
  42083. $key = \key($this->expires);
  42084. if ($key === null || $this->now() - $this->expires[$key] < 0) {
  42085. \reset($this->data);
  42086. $key = \key($this->data);
  42087. }
  42088. unset($this->data[$key], $this->expires[$key]);
  42089. }
  42090. return Promise\resolve(true);
  42091. }
  42092. public function delete($key)
  42093. {
  42094. unset($this->data[$key], $this->expires[$key]);
  42095. return Promise\resolve(true);
  42096. }
  42097. public function getMultiple(array $keys, $default = null)
  42098. {
  42099. $values = array();
  42100. foreach ($keys as $key) {
  42101. $values[$key] = $this->get($key, $default);
  42102. }
  42103. return Promise\all($values);
  42104. }
  42105. public function setMultiple(array $values, $ttl = null)
  42106. {
  42107. foreach ($values as $key => $value) {
  42108. $this->set($key, $value, $ttl);
  42109. }
  42110. return Promise\resolve(true);
  42111. }
  42112. public function deleteMultiple(array $keys)
  42113. {
  42114. foreach ($keys as $key) {
  42115. unset($this->data[$key], $this->expires[$key]);
  42116. }
  42117. return Promise\resolve(true);
  42118. }
  42119. public function clear()
  42120. {
  42121. $this->data = array();
  42122. $this->expires = array();
  42123. return Promise\resolve(true);
  42124. }
  42125. public function has($key)
  42126. {
  42127. if (isset($this->expires[$key]) && $this->now() - $this->expires[$key] > 0) {
  42128. unset($this->data[$key], $this->expires[$key]);
  42129. }
  42130. if (!\array_key_exists($key, $this->data)) {
  42131. return Promise\resolve(false);
  42132. }
  42133. $value = $this->data[$key];
  42134. unset($this->data[$key]);
  42135. $this->data[$key] = $value;
  42136. return Promise\resolve(true);
  42137. }
  42138. private function now()
  42139. {
  42140. return $this->supportsHighResolution ? \hrtime(true) * 1e-9 : \microtime(true);
  42141. }
  42142. }
  42143. <?php
  42144. namespace React\Stream;
  42145. use Evenement\EventEmitterInterface;
  42146. interface WritableStreamInterface extends EventEmitterInterface
  42147. {
  42148. public function isWritable();
  42149. public function write($data);
  42150. public function end($data = null);
  42151. public function close();
  42152. }
  42153. <?php
  42154. namespace React\Stream;
  42155. use Evenement\EventEmitter;
  42156. use React\EventLoop\Loop;
  42157. use React\EventLoop\LoopInterface;
  42158. final class WritableResourceStream extends EventEmitter implements WritableStreamInterface
  42159. {
  42160. private $stream;
  42161. private $loop;
  42162. private $softLimit;
  42163. private $writeChunkSize;
  42164. private $listening = false;
  42165. private $writable = true;
  42166. private $closed = false;
  42167. private $data = '';
  42168. public function __construct($stream, $loop = null, $writeBufferSoftLimit = null, $writeChunkSize = null)
  42169. {
  42170. if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
  42171. throw new \InvalidArgumentException('First parameter must be a valid stream resource');
  42172. }
  42173. $meta = \stream_get_meta_data($stream);
  42174. if (isset($meta['mode']) && $meta['mode'] !== '' && \strtr($meta['mode'], 'waxc+', '.....') === $meta['mode']) {
  42175. throw new \InvalidArgumentException('Given stream resource is not opened in write mode');
  42176. }
  42177. if (\stream_set_blocking($stream, false) !== true) {
  42178. throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
  42179. }
  42180. if ($loop !== null && !$loop instanceof LoopInterface) {
  42181. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  42182. }
  42183. $this->stream = $stream;
  42184. $this->loop = $loop ?: Loop::get();
  42185. $this->softLimit = ($writeBufferSoftLimit === null) ? 65536 : (int)$writeBufferSoftLimit;
  42186. $this->writeChunkSize = ($writeChunkSize === null) ? -1 : (int)$writeChunkSize;
  42187. }
  42188. public function isWritable()
  42189. {
  42190. return $this->writable;
  42191. }
  42192. public function write($data)
  42193. {
  42194. if (!$this->writable) {
  42195. return false;
  42196. }
  42197. $this->data .= $data;
  42198. if (!$this->listening && $this->data !== '') {
  42199. $this->listening = true;
  42200. $this->loop->addWriteStream($this->stream, array($this, 'handleWrite'));
  42201. }
  42202. return !isset($this->data[$this->softLimit - 1]);
  42203. }
  42204. public function end($data = null)
  42205. {
  42206. if (null !== $data) {
  42207. $this->write($data);
  42208. }
  42209. $this->writable = false;
  42210. if ($this->data === '') {
  42211. $this->close();
  42212. }
  42213. }
  42214. public function close()
  42215. {
  42216. if ($this->closed) {
  42217. return;
  42218. }
  42219. if ($this->listening) {
  42220. $this->listening = false;
  42221. $this->loop->removeWriteStream($this->stream);
  42222. }
  42223. $this->closed = true;
  42224. $this->writable = false;
  42225. $this->data = '';
  42226. $this->emit('close');
  42227. $this->removeAllListeners();
  42228. if (\is_resource($this->stream)) {
  42229. \fclose($this->stream);
  42230. }
  42231. }
  42232. public function handleWrite()
  42233. {
  42234. $error = null;
  42235. \set_error_handler(function ($_, $errstr) use (&$error) {
  42236. $error = $errstr;
  42237. });
  42238. if ($this->writeChunkSize === -1) {
  42239. $sent = \fwrite($this->stream, $this->data);
  42240. } else {
  42241. $sent = \fwrite($this->stream, $this->data, $this->writeChunkSize);
  42242. }
  42243. \restore_error_handler();
  42244. if (($sent === 0 || $sent === false) && $error !== null) {
  42245. $this->emit('error', array(new \RuntimeException('Unable to write to stream: ' . $error)));
  42246. $this->close();
  42247. return;
  42248. }
  42249. $exceeded = isset($this->data[$this->softLimit - 1]);
  42250. $this->data = (string) \substr($this->data, $sent);
  42251. if ($exceeded && !isset($this->data[$this->softLimit - 1])) {
  42252. $this->emit('drain');
  42253. }
  42254. if ($this->data === '') {
  42255. if ($this->listening) {
  42256. $this->loop->removeWriteStream($this->stream);
  42257. $this->listening = false;
  42258. }
  42259. if (!$this->writable) {
  42260. $this->close();
  42261. }
  42262. }
  42263. }
  42264. }
  42265. <?php
  42266. namespace React\Stream;
  42267. use Evenement\EventEmitterInterface;
  42268. interface ReadableStreamInterface extends EventEmitterInterface
  42269. {
  42270. public function isReadable();
  42271. public function pause();
  42272. public function resume();
  42273. public function pipe(WritableStreamInterface $dest, array $options = array());
  42274. public function close();
  42275. }
  42276. <?php
  42277. namespace React\Stream;
  42278. use Evenement\EventEmitter;
  42279. use React\EventLoop\Loop;
  42280. use React\EventLoop\LoopInterface;
  42281. use InvalidArgumentException;
  42282. final class ReadableResourceStream extends EventEmitter implements ReadableStreamInterface
  42283. {
  42284. private $stream;
  42285. private $loop;
  42286. private $bufferSize;
  42287. private $closed = false;
  42288. private $listening = false;
  42289. public function __construct($stream, $loop = null, $readChunkSize = null)
  42290. {
  42291. if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
  42292. throw new InvalidArgumentException('First parameter must be a valid stream resource');
  42293. }
  42294. $meta = \stream_get_meta_data($stream);
  42295. if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], 'r') === \strpos($meta['mode'], '+')) {
  42296. throw new InvalidArgumentException('Given stream resource is not opened in read mode');
  42297. }
  42298. if (\stream_set_blocking($stream, false) !== true) {
  42299. throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
  42300. }
  42301. if ($loop !== null && !$loop instanceof LoopInterface) {
  42302. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  42303. }
  42304. if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
  42305. \stream_set_read_buffer($stream, 0);
  42306. }
  42307. $this->stream = $stream;
  42308. $this->loop = $loop ?: Loop::get();
  42309. $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize;
  42310. $this->resume();
  42311. }
  42312. public function isReadable()
  42313. {
  42314. return !$this->closed;
  42315. }
  42316. public function pause()
  42317. {
  42318. if ($this->listening) {
  42319. $this->loop->removeReadStream($this->stream);
  42320. $this->listening = false;
  42321. }
  42322. }
  42323. public function resume()
  42324. {
  42325. if (!$this->listening && !$this->closed) {
  42326. $this->loop->addReadStream($this->stream, array($this, 'handleData'));
  42327. $this->listening = true;
  42328. }
  42329. }
  42330. public function pipe(WritableStreamInterface $dest, array $options = array())
  42331. {
  42332. return Util::pipe($this, $dest, $options);
  42333. }
  42334. public function close()
  42335. {
  42336. if ($this->closed) {
  42337. return;
  42338. }
  42339. $this->closed = true;
  42340. $this->emit('close');
  42341. $this->pause();
  42342. $this->removeAllListeners();
  42343. if (\is_resource($this->stream)) {
  42344. \fclose($this->stream);
  42345. }
  42346. }
  42347. public function handleData()
  42348. {
  42349. $error = null;
  42350. \set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$error) {
  42351. $error = new \ErrorException(
  42352. $errstr,
  42353. 0,
  42354. $errno,
  42355. $errfile,
  42356. $errline
  42357. );
  42358. });
  42359. $data = \stream_get_contents($this->stream, $this->bufferSize);
  42360. \restore_error_handler();
  42361. if ($error !== null) {
  42362. $this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
  42363. $this->close();
  42364. return;
  42365. }
  42366. if ($data !== '') {
  42367. $this->emit('data', array($data));
  42368. } elseif (\feof($this->stream)) {
  42369. $this->emit('end');
  42370. $this->close();
  42371. }
  42372. }
  42373. private function isLegacyPipe($resource)
  42374. {
  42375. if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
  42376. $meta = \stream_get_meta_data($resource);
  42377. if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
  42378. return true;
  42379. }
  42380. }
  42381. return false;
  42382. }
  42383. }
  42384. <?php
  42385. namespace React\Stream;
  42386. interface DuplexStreamInterface extends ReadableStreamInterface, WritableStreamInterface
  42387. {
  42388. }
  42389. <?php
  42390. namespace React\Stream;
  42391. use Evenement\EventEmitter;
  42392. use InvalidArgumentException;
  42393. final class ThroughStream extends EventEmitter implements DuplexStreamInterface
  42394. {
  42395. private $readable = true;
  42396. private $writable = true;
  42397. private $closed = false;
  42398. private $paused = false;
  42399. private $drain = false;
  42400. private $callback;
  42401. public function __construct($callback = null)
  42402. {
  42403. if ($callback !== null && !\is_callable($callback)) {
  42404. throw new InvalidArgumentException('Invalid transformation callback given');
  42405. }
  42406. $this->callback = $callback;
  42407. }
  42408. public function pause()
  42409. {
  42410. $this->paused = $this->readable;
  42411. }
  42412. public function resume()
  42413. {
  42414. $this->paused = false;
  42415. if ($this->drain) {
  42416. $this->drain = false;
  42417. $this->emit('drain');
  42418. }
  42419. }
  42420. public function pipe(WritableStreamInterface $dest, array $options = array())
  42421. {
  42422. return Util::pipe($this, $dest, $options);
  42423. }
  42424. public function isReadable()
  42425. {
  42426. return $this->readable;
  42427. }
  42428. public function isWritable()
  42429. {
  42430. return $this->writable;
  42431. }
  42432. public function write($data)
  42433. {
  42434. if (!$this->writable) {
  42435. return false;
  42436. }
  42437. if ($this->callback !== null) {
  42438. try {
  42439. $data = \call_user_func($this->callback, $data);
  42440. } catch (\Exception $e) {
  42441. $this->emit('error', array($e));
  42442. $this->close();
  42443. return false;
  42444. }
  42445. }
  42446. $this->emit('data', array($data));
  42447. if ($this->paused) {
  42448. $this->drain = true;
  42449. }
  42450. return $this->writable && !$this->paused;
  42451. }
  42452. public function end($data = null)
  42453. {
  42454. if (!$this->writable) {
  42455. return;
  42456. }
  42457. if (null !== $data) {
  42458. $this->write($data);
  42459. if (!$this->writable) {
  42460. return;
  42461. }
  42462. }
  42463. $this->readable = false;
  42464. $this->writable = false;
  42465. $this->paused = false;
  42466. $this->drain = false;
  42467. $this->emit('end');
  42468. $this->close();
  42469. }
  42470. public function close()
  42471. {
  42472. if ($this->closed) {
  42473. return;
  42474. }
  42475. $this->readable = false;
  42476. $this->writable = false;
  42477. $this->paused = false;
  42478. $this->drain = false;
  42479. $this->closed = true;
  42480. $this->callback = null;
  42481. $this->emit('close');
  42482. $this->removeAllListeners();
  42483. }
  42484. }
  42485. <?php
  42486. namespace React\Stream;
  42487. final class Util
  42488. {
  42489. public static function pipe(ReadableStreamInterface $source, WritableStreamInterface $dest, array $options = array())
  42490. {
  42491. if (!$source->isReadable()) {
  42492. return $dest;
  42493. }
  42494. if (!$dest->isWritable()) {
  42495. $source->pause();
  42496. return $dest;
  42497. }
  42498. $dest->emit('pipe', array($source));
  42499. $source->on('data', $dataer = function ($data) use ($source, $dest) {
  42500. $feedMore = $dest->write($data);
  42501. if (false === $feedMore) {
  42502. $source->pause();
  42503. }
  42504. });
  42505. $dest->on('close', function () use ($source, $dataer) {
  42506. $source->removeListener('data', $dataer);
  42507. $source->pause();
  42508. });
  42509. $dest->on('drain', $drainer = function () use ($source) {
  42510. $source->resume();
  42511. });
  42512. $source->on('close', function () use ($dest, $drainer) {
  42513. $dest->removeListener('drain', $drainer);
  42514. });
  42515. $end = isset($options['end']) ? $options['end'] : true;
  42516. if ($end) {
  42517. $source->on('end', $ender = function () use ($dest) {
  42518. $dest->end();
  42519. });
  42520. $dest->on('close', function () use ($source, $ender) {
  42521. $source->removeListener('end', $ender);
  42522. });
  42523. }
  42524. return $dest;
  42525. }
  42526. public static function forwardEvents($source, $target, array $events)
  42527. {
  42528. foreach ($events as $event) {
  42529. $source->on($event, function () use ($event, $target) {
  42530. $target->emit($event, \func_get_args());
  42531. });
  42532. }
  42533. }
  42534. }
  42535. <?php
  42536. namespace React\Stream;
  42537. use Evenement\EventEmitter;
  42538. final class CompositeStream extends EventEmitter implements DuplexStreamInterface
  42539. {
  42540. private $readable;
  42541. private $writable;
  42542. private $closed = false;
  42543. public function __construct(ReadableStreamInterface $readable, WritableStreamInterface $writable)
  42544. {
  42545. $this->readable = $readable;
  42546. $this->writable = $writable;
  42547. if (!$readable->isReadable() || !$writable->isWritable()) {
  42548. $this->close();
  42549. return;
  42550. }
  42551. Util::forwardEvents($this->readable, $this, array('data', 'end', 'error'));
  42552. Util::forwardEvents($this->writable, $this, array('drain', 'error', 'pipe'));
  42553. $this->readable->on('close', array($this, 'close'));
  42554. $this->writable->on('close', array($this, 'close'));
  42555. }
  42556. public function isReadable()
  42557. {
  42558. return $this->readable->isReadable();
  42559. }
  42560. public function pause()
  42561. {
  42562. $this->readable->pause();
  42563. }
  42564. public function resume()
  42565. {
  42566. if (!$this->writable->isWritable()) {
  42567. return;
  42568. }
  42569. $this->readable->resume();
  42570. }
  42571. public function pipe(WritableStreamInterface $dest, array $options = array())
  42572. {
  42573. return Util::pipe($this, $dest, $options);
  42574. }
  42575. public function isWritable()
  42576. {
  42577. return $this->writable->isWritable();
  42578. }
  42579. public function write($data)
  42580. {
  42581. return $this->writable->write($data);
  42582. }
  42583. public function end($data = null)
  42584. {
  42585. $this->readable->pause();
  42586. $this->writable->end($data);
  42587. }
  42588. public function close()
  42589. {
  42590. if ($this->closed) {
  42591. return;
  42592. }
  42593. $this->closed = true;
  42594. $this->readable->close();
  42595. $this->writable->close();
  42596. $this->emit('close');
  42597. $this->removeAllListeners();
  42598. }
  42599. }
  42600. <?php
  42601. namespace React\Stream;
  42602. use Evenement\EventEmitter;
  42603. use React\EventLoop\Loop;
  42604. use React\EventLoop\LoopInterface;
  42605. use InvalidArgumentException;
  42606. final class DuplexResourceStream extends EventEmitter implements DuplexStreamInterface
  42607. {
  42608. private $stream;
  42609. private $loop;
  42610. private $bufferSize;
  42611. private $buffer;
  42612. private $readable = true;
  42613. private $writable = true;
  42614. private $closing = false;
  42615. private $listening = false;
  42616. public function __construct($stream, $loop = null, $readChunkSize = null, $buffer = null)
  42617. {
  42618. if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
  42619. throw new InvalidArgumentException('First parameter must be a valid stream resource');
  42620. }
  42621. $meta = \stream_get_meta_data($stream);
  42622. if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], '+') === false) {
  42623. throw new InvalidArgumentException('Given stream resource is not opened in read and write mode');
  42624. }
  42625. if ($buffer !== null && !$buffer instanceof WritableResourceStream && \stream_set_blocking($stream, false) !== true) {
  42626. throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
  42627. }
  42628. if ($loop !== null && !$loop instanceof LoopInterface) {
  42629. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  42630. }
  42631. if ($buffer !== null && !$buffer instanceof WritableStreamInterface) {
  42632. throw new \InvalidArgumentException('Argument #4 ($buffer) expected null|React\Stream\WritableStreamInterface');
  42633. }
  42634. if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
  42635. \stream_set_read_buffer($stream, 0);
  42636. }
  42637. if ($buffer === null) {
  42638. $buffer = new WritableResourceStream($stream, $loop);
  42639. }
  42640. $this->stream = $stream;
  42641. $this->loop = $loop ?: Loop::get();
  42642. $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize;
  42643. $this->buffer = $buffer;
  42644. $that = $this;
  42645. $this->buffer->on('error', function ($error) use ($that) {
  42646. $that->emit('error', array($error));
  42647. });
  42648. $this->buffer->on('close', array($this, 'close'));
  42649. $this->buffer->on('drain', function () use ($that) {
  42650. $that->emit('drain');
  42651. });
  42652. $this->resume();
  42653. }
  42654. public function isReadable()
  42655. {
  42656. return $this->readable;
  42657. }
  42658. public function isWritable()
  42659. {
  42660. return $this->writable;
  42661. }
  42662. public function pause()
  42663. {
  42664. if ($this->listening) {
  42665. $this->loop->removeReadStream($this->stream);
  42666. $this->listening = false;
  42667. }
  42668. }
  42669. public function resume()
  42670. {
  42671. if (!$this->listening && $this->readable) {
  42672. $this->loop->addReadStream($this->stream, array($this, 'handleData'));
  42673. $this->listening = true;
  42674. }
  42675. }
  42676. public function write($data)
  42677. {
  42678. if (!$this->writable) {
  42679. return false;
  42680. }
  42681. return $this->buffer->write($data);
  42682. }
  42683. public function close()
  42684. {
  42685. if (!$this->writable && !$this->closing) {
  42686. return;
  42687. }
  42688. $this->closing = false;
  42689. $this->readable = false;
  42690. $this->writable = false;
  42691. $this->emit('close');
  42692. $this->pause();
  42693. $this->buffer->close();
  42694. $this->removeAllListeners();
  42695. if (\is_resource($this->stream)) {
  42696. \fclose($this->stream);
  42697. }
  42698. }
  42699. public function end($data = null)
  42700. {
  42701. if (!$this->writable) {
  42702. return;
  42703. }
  42704. $this->closing = true;
  42705. $this->readable = false;
  42706. $this->writable = false;
  42707. $this->pause();
  42708. $this->buffer->end($data);
  42709. }
  42710. public function pipe(WritableStreamInterface $dest, array $options = array())
  42711. {
  42712. return Util::pipe($this, $dest, $options);
  42713. }
  42714. public function handleData($stream)
  42715. {
  42716. $error = null;
  42717. \set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$error) {
  42718. $error = new \ErrorException(
  42719. $errstr,
  42720. 0,
  42721. $errno,
  42722. $errfile,
  42723. $errline
  42724. );
  42725. });
  42726. $data = \stream_get_contents($stream, $this->bufferSize);
  42727. \restore_error_handler();
  42728. if ($error !== null) {
  42729. $this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
  42730. $this->close();
  42731. return;
  42732. }
  42733. if ($data !== '') {
  42734. $this->emit('data', array($data));
  42735. } elseif (\feof($this->stream)) {
  42736. $this->emit('end');
  42737. $this->close();
  42738. }
  42739. }
  42740. private function isLegacyPipe($resource)
  42741. {
  42742. if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
  42743. $meta = \stream_get_meta_data($resource);
  42744. if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
  42745. return true;
  42746. }
  42747. }
  42748. return false;
  42749. }
  42750. }
  42751. <?php
  42752. namespace React\Promise;
  42753. /**
  42754. @template-covariant
  42755. */
  42756. interface PromiseInterface
  42757. {
  42758. /**
  42759. @template
  42760. @template
  42761. */
  42762. public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface;
  42763. /**
  42764. @template
  42765. @template
  42766. */
  42767. public function catch(callable $onRejected): PromiseInterface;
  42768. public function finally(callable $onFulfilledOrRejected): PromiseInterface;
  42769. public function cancel(): void;
  42770. /**
  42771. @template
  42772. @template
  42773. */
  42774. public function otherwise(callable $onRejected): PromiseInterface;
  42775. public function always(callable $onFulfilledOrRejected): PromiseInterface;
  42776. }
  42777. <?php
  42778. namespace React\Promise;
  42779. use React\Promise\Exception\CompositeException;
  42780. use React\Promise\Internal\FulfilledPromise;
  42781. use React\Promise\Internal\RejectedPromise;
  42782. /**
  42783. @template
  42784. */
  42785. function resolve($promiseOrValue): PromiseInterface
  42786. {
  42787. if ($promiseOrValue instanceof PromiseInterface) {
  42788. return $promiseOrValue;
  42789. }
  42790. if (\is_object($promiseOrValue) && \method_exists($promiseOrValue, 'then')) {
  42791. $canceller = null;
  42792. if (\method_exists($promiseOrValue, 'cancel')) {
  42793. $canceller = [$promiseOrValue, 'cancel'];
  42794. assert(\is_callable($canceller));
  42795. }
  42796. return new Promise(function (callable $resolve, callable $reject) use ($promiseOrValue): void {
  42797. $promiseOrValue->then($resolve, $reject);
  42798. }, $canceller);
  42799. }
  42800. return new FulfilledPromise($promiseOrValue);
  42801. }
  42802. function reject(\Throwable $reason): PromiseInterface
  42803. {
  42804. return new RejectedPromise($reason);
  42805. }
  42806. /**
  42807. @template
  42808. */
  42809. function all(iterable $promisesOrValues): PromiseInterface
  42810. {
  42811. $cancellationQueue = new Internal\CancellationQueue();
  42812. return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
  42813. $toResolve = 0;
  42814. $continue = true;
  42815. $values = [];
  42816. foreach ($promisesOrValues as $i => $promiseOrValue) {
  42817. $cancellationQueue->enqueue($promiseOrValue);
  42818. $values[$i] = null;
  42819. ++$toResolve;
  42820. resolve($promiseOrValue)->then(
  42821. function ($value) use ($i, &$values, &$toResolve, &$continue, $resolve): void {
  42822. $values[$i] = $value;
  42823. if (0 === --$toResolve && !$continue) {
  42824. $resolve($values);
  42825. }
  42826. },
  42827. function (\Throwable $reason) use (&$continue, $reject): void {
  42828. $continue = false;
  42829. $reject($reason);
  42830. }
  42831. );
  42832. if (!$continue && !\is_array($promisesOrValues)) {
  42833. break;
  42834. }
  42835. }
  42836. $continue = false;
  42837. if ($toResolve === 0) {
  42838. $resolve($values);
  42839. }
  42840. }, $cancellationQueue);
  42841. }
  42842. /**
  42843. @template
  42844. */
  42845. function race(iterable $promisesOrValues): PromiseInterface
  42846. {
  42847. $cancellationQueue = new Internal\CancellationQueue();
  42848. return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
  42849. $continue = true;
  42850. foreach ($promisesOrValues as $promiseOrValue) {
  42851. $cancellationQueue->enqueue($promiseOrValue);
  42852. resolve($promiseOrValue)->then($resolve, $reject)->finally(function () use (&$continue): void {
  42853. $continue = false;
  42854. });
  42855. if (!$continue && !\is_array($promisesOrValues)) {
  42856. break;
  42857. }
  42858. }
  42859. }, $cancellationQueue);
  42860. }
  42861. /**
  42862. @template
  42863. */
  42864. function any(iterable $promisesOrValues): PromiseInterface
  42865. {
  42866. $cancellationQueue = new Internal\CancellationQueue();
  42867. return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
  42868. $toReject = 0;
  42869. $continue = true;
  42870. $reasons = [];
  42871. foreach ($promisesOrValues as $i => $promiseOrValue) {
  42872. $cancellationQueue->enqueue($promiseOrValue);
  42873. ++$toReject;
  42874. resolve($promiseOrValue)->then(
  42875. function ($value) use ($resolve, &$continue): void {
  42876. $continue = false;
  42877. $resolve($value);
  42878. },
  42879. function (\Throwable $reason) use ($i, &$reasons, &$toReject, $reject, &$continue): void {
  42880. $reasons[$i] = $reason;
  42881. if (0 === --$toReject && !$continue) {
  42882. $reject(new CompositeException(
  42883. $reasons,
  42884. 'All promises rejected.'
  42885. ));
  42886. }
  42887. }
  42888. );
  42889. if (!$continue && !\is_array($promisesOrValues)) {
  42890. break;
  42891. }
  42892. }
  42893. $continue = false;
  42894. if ($toReject === 0 && !$reasons) {
  42895. $reject(new Exception\LengthException(
  42896. 'Must contain at least 1 item but contains only 0 items.'
  42897. ));
  42898. } elseif ($toReject === 0) {
  42899. $reject(new CompositeException(
  42900. $reasons,
  42901. 'All promises rejected.'
  42902. ));
  42903. }
  42904. }, $cancellationQueue);
  42905. }
  42906. function set_rejection_handler(?callable $callback): ?callable
  42907. {
  42908. static $current = null;
  42909. $previous = $current;
  42910. $current = $callback;
  42911. return $previous;
  42912. }
  42913. function _checkTypehint(callable $callback, \Throwable $reason): bool
  42914. {
  42915. if (\is_array($callback)) {
  42916. $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
  42917. } elseif (\is_object($callback) && !$callback instanceof \Closure) {
  42918. $callbackReflection = new \ReflectionMethod($callback, '__invoke');
  42919. } else {
  42920. assert($callback instanceof \Closure || \is_string($callback));
  42921. $callbackReflection = new \ReflectionFunction($callback);
  42922. }
  42923. $parameters = $callbackReflection->getParameters();
  42924. if (!isset($parameters[0])) {
  42925. return true;
  42926. }
  42927. $expectedException = $parameters[0];
  42928. $type = $expectedException->getType();
  42929. $isTypeUnion = true;
  42930. $types = [];
  42931. switch (true) {
  42932. case $type === null:
  42933. break;
  42934. case $type instanceof \ReflectionNamedType:
  42935. $types = [$type];
  42936. break;
  42937. case $type instanceof \ReflectionIntersectionType:
  42938. $isTypeUnion = false;
  42939. case $type instanceof \ReflectionUnionType;
  42940. $types = $type->getTypes();
  42941. break;
  42942. default:
  42943. throw new \LogicException('Unexpected return value of ReflectionParameter::getType');
  42944. }
  42945. if (empty($types)) {
  42946. return true;
  42947. }
  42948. foreach ($types as $type) {
  42949. if ($type instanceof \ReflectionIntersectionType) {
  42950. foreach ($type->getTypes() as $typeToMatch) {
  42951. assert($typeToMatch instanceof \ReflectionNamedType);
  42952. $name = $typeToMatch->getName();
  42953. if (!($matches = (!$typeToMatch->isBuiltin() && $reason instanceof $name))) {
  42954. break;
  42955. }
  42956. }
  42957. assert(isset($matches));
  42958. } else {
  42959. assert($type instanceof \ReflectionNamedType);
  42960. $name = $type->getName();
  42961. $matches = !$type->isBuiltin() && $reason instanceof $name;
  42962. }
  42963. if ($matches) {
  42964. if ($isTypeUnion) {
  42965. return true;
  42966. }
  42967. } else {
  42968. if (!$isTypeUnion) {
  42969. return false;
  42970. }
  42971. }
  42972. }
  42973. return $isTypeUnion ? false : true;
  42974. }
  42975. <?php
  42976. if (!\function_exists('React\Promise\resolve')) {
  42977. require __DIR__.'/functions.php';
  42978. }
  42979. <?php
  42980. namespace React\Promise;
  42981. use React\Promise\Internal\RejectedPromise;
  42982. /**
  42983. @template
  42984. @template-implements
  42985. */
  42986. final class Promise implements PromiseInterface
  42987. {
  42988. private $canceller;
  42989. private $result;
  42990. private $handlers = [];
  42991. private $requiredCancelRequests = 0;
  42992. private $cancelled = false;
  42993. public function __construct(callable $resolver, ?callable $canceller = null)
  42994. {
  42995. $this->canceller = $canceller;
  42996. $cb = $resolver;
  42997. $resolver = $canceller = null;
  42998. $this->call($cb);
  42999. }
  43000. public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
  43001. {
  43002. if (null !== $this->result) {
  43003. return $this->result->then($onFulfilled, $onRejected);
  43004. }
  43005. if (null === $this->canceller) {
  43006. return new static($this->resolver($onFulfilled, $onRejected));
  43007. }
  43008. $parent = $this;
  43009. ++$parent->requiredCancelRequests;
  43010. return new static(
  43011. $this->resolver($onFulfilled, $onRejected),
  43012. static function () use (&$parent): void {
  43013. assert($parent instanceof self);
  43014. --$parent->requiredCancelRequests;
  43015. if ($parent->requiredCancelRequests <= 0) {
  43016. $parent->cancel();
  43017. }
  43018. $parent = null;
  43019. }
  43020. );
  43021. }
  43022. /**
  43023. @template
  43024. @template
  43025. */
  43026. public function catch(callable $onRejected): PromiseInterface
  43027. {
  43028. return $this->then(null, static function (\Throwable $reason) use ($onRejected) {
  43029. if (!_checkTypehint($onRejected, $reason)) {
  43030. return new RejectedPromise($reason);
  43031. }
  43032. return $onRejected($reason);
  43033. });
  43034. }
  43035. public function finally(callable $onFulfilledOrRejected): PromiseInterface
  43036. {
  43037. return $this->then(static function ($value) use ($onFulfilledOrRejected): PromiseInterface {
  43038. return resolve($onFulfilledOrRejected())->then(function () use ($value) {
  43039. return $value;
  43040. });
  43041. }, static function (\Throwable $reason) use ($onFulfilledOrRejected): PromiseInterface {
  43042. return resolve($onFulfilledOrRejected())->then(function () use ($reason): RejectedPromise {
  43043. return new RejectedPromise($reason);
  43044. });
  43045. });
  43046. }
  43047. public function cancel(): void
  43048. {
  43049. $this->cancelled = true;
  43050. $canceller = $this->canceller;
  43051. $this->canceller = null;
  43052. $parentCanceller = null;
  43053. if (null !== $this->result) {
  43054. if ($this->result instanceof RejectedPromise) {
  43055. $this->result->cancel();
  43056. }
  43057. $root = $this->unwrap($this->result);
  43058. if (!$root instanceof self || null !== $root->result) {
  43059. return;
  43060. }
  43061. $root->requiredCancelRequests--;
  43062. if ($root->requiredCancelRequests <= 0) {
  43063. $parentCanceller = [$root, 'cancel'];
  43064. }
  43065. }
  43066. if (null !== $canceller) {
  43067. $this->call($canceller);
  43068. }
  43069. if ($parentCanceller) {
  43070. $parentCanceller();
  43071. }
  43072. }
  43073. public function otherwise(callable $onRejected): PromiseInterface
  43074. {
  43075. return $this->catch($onRejected);
  43076. }
  43077. public function always(callable $onFulfilledOrRejected): PromiseInterface
  43078. {
  43079. return $this->finally($onFulfilledOrRejected);
  43080. }
  43081. private function resolver(?callable $onFulfilled = null, ?callable $onRejected = null): callable
  43082. {
  43083. return function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected): void {
  43084. $this->handlers[] = static function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject): void {
  43085. $promise = $promise->then($onFulfilled, $onRejected);
  43086. if ($promise instanceof self && $promise->result === null) {
  43087. $promise->handlers[] = static function (PromiseInterface $promise) use ($resolve, $reject): void {
  43088. $promise->then($resolve, $reject);
  43089. };
  43090. } else {
  43091. $promise->then($resolve, $reject);
  43092. }
  43093. };
  43094. };
  43095. }
  43096. private function reject(\Throwable $reason): void
  43097. {
  43098. if (null !== $this->result) {
  43099. return;
  43100. }
  43101. $this->settle(reject($reason));
  43102. }
  43103. private function settle(PromiseInterface $result): void
  43104. {
  43105. $result = $this->unwrap($result);
  43106. if ($result === $this) {
  43107. $result = new RejectedPromise(
  43108. new \LogicException('Cannot resolve a promise with itself.')
  43109. );
  43110. }
  43111. if ($result instanceof self) {
  43112. $result->requiredCancelRequests++;
  43113. } else {
  43114. $this->canceller = null;
  43115. }
  43116. $handlers = $this->handlers;
  43117. $this->handlers = [];
  43118. $this->result = $result;
  43119. foreach ($handlers as $handler) {
  43120. $handler($result);
  43121. }
  43122. if ($this->cancelled && $result instanceof RejectedPromise) {
  43123. $result->cancel();
  43124. }
  43125. }
  43126. private function unwrap(PromiseInterface $promise): PromiseInterface
  43127. {
  43128. while ($promise instanceof self && null !== $promise->result) {
  43129. $promise = $promise->result;
  43130. }
  43131. return $promise;
  43132. }
  43133. private function call(callable $cb): void
  43134. {
  43135. $callback = $cb;
  43136. $cb = null;
  43137. if (\is_array($callback)) {
  43138. $ref = new \ReflectionMethod($callback[0], $callback[1]);
  43139. } elseif (\is_object($callback) && !$callback instanceof \Closure) {
  43140. $ref = new \ReflectionMethod($callback, '__invoke');
  43141. } else {
  43142. assert($callback instanceof \Closure || \is_string($callback));
  43143. $ref = new \ReflectionFunction($callback);
  43144. }
  43145. $args = $ref->getNumberOfParameters();
  43146. try {
  43147. if ($args === 0) {
  43148. $callback();
  43149. } else {
  43150. $target =& $this;
  43151. $callback(
  43152. static function ($value) use (&$target): void {
  43153. if ($target !== null) {
  43154. $target->settle(resolve($value));
  43155. $target = null;
  43156. }
  43157. },
  43158. static function (\Throwable $reason) use (&$target): void {
  43159. if ($target !== null) {
  43160. $target->reject($reason);
  43161. $target = null;
  43162. }
  43163. }
  43164. );
  43165. }
  43166. } catch (\Throwable $e) {
  43167. $target = null;
  43168. $this->reject($e);
  43169. }
  43170. }
  43171. }
  43172. <?php
  43173. namespace React\Promise;
  43174. /**
  43175. @template
  43176. */
  43177. final class Deferred
  43178. {
  43179. private $promise;
  43180. private $resolveCallback;
  43181. private $rejectCallback;
  43182. public function __construct(?callable $canceller = null)
  43183. {
  43184. $this->promise = new Promise(function ($resolve, $reject): void {
  43185. $this->resolveCallback = $resolve;
  43186. $this->rejectCallback = $reject;
  43187. }, $canceller);
  43188. }
  43189. public function promise(): PromiseInterface
  43190. {
  43191. return $this->promise;
  43192. }
  43193. public function resolve($value): void
  43194. {
  43195. ($this->resolveCallback)($value);
  43196. }
  43197. public function reject(\Throwable $reason): void
  43198. {
  43199. ($this->rejectCallback)($reason);
  43200. }
  43201. }
  43202. <?php
  43203. namespace React\Promise\Internal;
  43204. use React\Promise\PromiseInterface;
  43205. use function React\Promise\_checkTypehint;
  43206. use function React\Promise\resolve;
  43207. use function React\Promise\set_rejection_handler;
  43208. /**
  43209. @template-implements
  43210. */
  43211. final class RejectedPromise implements PromiseInterface
  43212. {
  43213. private $reason;
  43214. private $handled = false;
  43215. public function __construct(\Throwable $reason)
  43216. {
  43217. $this->reason = $reason;
  43218. }
  43219. public function __destruct()
  43220. {
  43221. if ($this->handled) {
  43222. return;
  43223. }
  43224. $handler = set_rejection_handler(null);
  43225. if ($handler === null) {
  43226. $message = 'Unhandled promise rejection with ' . $this->reason;
  43227. \error_log($message);
  43228. return;
  43229. }
  43230. try {
  43231. $handler($this->reason);
  43232. } catch (\Throwable $e) {
  43233. \preg_match('/^([^:\s]++)(.*+)$/sm', (string) $e, $match);
  43234. \assert(isset($match[1], $match[2]));
  43235. $message = 'Fatal error: Uncaught ' . $match[1] . ' from unhandled promise rejection handler' . $match[2];
  43236. \error_log($message);
  43237. exit(255);
  43238. }
  43239. }
  43240. /**
  43241. @template
  43242. */
  43243. public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
  43244. {
  43245. if (null === $onRejected) {
  43246. return $this;
  43247. }
  43248. $this->handled = true;
  43249. try {
  43250. return resolve($onRejected($this->reason));
  43251. } catch (\Throwable $exception) {
  43252. return new RejectedPromise($exception);
  43253. }
  43254. }
  43255. /**
  43256. @template
  43257. @template
  43258. */
  43259. public function catch(callable $onRejected): PromiseInterface
  43260. {
  43261. if (!_checkTypehint($onRejected, $this->reason)) {
  43262. return $this;
  43263. }
  43264. return $this->then(null, $onRejected);
  43265. }
  43266. public function finally(callable $onFulfilledOrRejected): PromiseInterface
  43267. {
  43268. return $this->then(null, function (\Throwable $reason) use ($onFulfilledOrRejected): PromiseInterface {
  43269. return resolve($onFulfilledOrRejected())->then(function () use ($reason): PromiseInterface {
  43270. return new RejectedPromise($reason);
  43271. });
  43272. });
  43273. }
  43274. public function cancel(): void
  43275. {
  43276. $this->handled = true;
  43277. }
  43278. public function otherwise(callable $onRejected): PromiseInterface
  43279. {
  43280. return $this->catch($onRejected);
  43281. }
  43282. public function always(callable $onFulfilledOrRejected): PromiseInterface
  43283. {
  43284. return $this->finally($onFulfilledOrRejected);
  43285. }
  43286. }
  43287. <?php
  43288. namespace React\Promise\Internal;
  43289. use React\Promise\PromiseInterface;
  43290. use function React\Promise\resolve;
  43291. /**
  43292. @template
  43293. @template-implements
  43294. */
  43295. final class FulfilledPromise implements PromiseInterface
  43296. {
  43297. private $value;
  43298. public function __construct($value = null)
  43299. {
  43300. if ($value instanceof PromiseInterface) {
  43301. throw new \InvalidArgumentException('You cannot create React\Promise\FulfilledPromise with a promise. Use React\Promise\resolve($promiseOrValue) instead.');
  43302. }
  43303. $this->value = $value;
  43304. }
  43305. /**
  43306. @template
  43307. */
  43308. public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
  43309. {
  43310. if (null === $onFulfilled) {
  43311. return $this;
  43312. }
  43313. try {
  43314. $result = $onFulfilled($this->value);
  43315. return resolve($result);
  43316. } catch (\Throwable $exception) {
  43317. return new RejectedPromise($exception);
  43318. }
  43319. }
  43320. public function catch(callable $onRejected): PromiseInterface
  43321. {
  43322. return $this;
  43323. }
  43324. public function finally(callable $onFulfilledOrRejected): PromiseInterface
  43325. {
  43326. return $this->then(function ($value) use ($onFulfilledOrRejected): PromiseInterface {
  43327. return resolve($onFulfilledOrRejected())->then(function () use ($value) {
  43328. return $value;
  43329. });
  43330. });
  43331. }
  43332. public function cancel(): void
  43333. {
  43334. }
  43335. public function otherwise(callable $onRejected): PromiseInterface
  43336. {
  43337. return $this->catch($onRejected);
  43338. }
  43339. public function always(callable $onFulfilledOrRejected): PromiseInterface
  43340. {
  43341. return $this->finally($onFulfilledOrRejected);
  43342. }
  43343. }
  43344. <?php
  43345. namespace React\Promise\Internal;
  43346. final class CancellationQueue
  43347. {
  43348. private $started = false;
  43349. private $queue = [];
  43350. public function __invoke(): void
  43351. {
  43352. if ($this->started) {
  43353. return;
  43354. }
  43355. $this->started = true;
  43356. $this->drain();
  43357. }
  43358. public function enqueue($cancellable): void
  43359. {
  43360. if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) {
  43361. return;
  43362. }
  43363. $length = \array_push($this->queue, $cancellable);
  43364. if ($this->started && 1 === $length) {
  43365. $this->drain();
  43366. }
  43367. }
  43368. private function drain(): void
  43369. {
  43370. for ($i = \key($this->queue); isset($this->queue[$i]); $i++) {
  43371. $cancellable = $this->queue[$i];
  43372. assert(\method_exists($cancellable, 'cancel'));
  43373. $exception = null;
  43374. try {
  43375. $cancellable->cancel();
  43376. } catch (\Throwable $exception) {
  43377. }
  43378. unset($this->queue[$i]);
  43379. if ($exception) {
  43380. throw $exception;
  43381. }
  43382. }
  43383. $this->queue = [];
  43384. }
  43385. }
  43386. <?php
  43387. namespace React\Promise\Exception;
  43388. class LengthException extends \LengthException
  43389. {
  43390. }
  43391. <?php
  43392. namespace React\Promise\Exception;
  43393. class CompositeException extends \Exception
  43394. {
  43395. private $throwables;
  43396. public function __construct(array $throwables, string $message = '', int $code = 0, ?\Throwable $previous = null)
  43397. {
  43398. parent::__construct($message, $code, $previous);
  43399. $this->throwables = $throwables;
  43400. }
  43401. public function getThrowables(): array
  43402. {
  43403. return $this->throwables;
  43404. }
  43405. }
  43406. <?php
  43407. namespace React\Dns;
  43408. final class RecordNotFoundException extends \Exception
  43409. {
  43410. }
  43411. <?php
  43412. namespace React\Dns;
  43413. final class BadServerException extends \Exception
  43414. {
  43415. }
  43416. <?php
  43417. namespace React\Dns\Config;
  43418. use RuntimeException;
  43419. final class Config
  43420. {
  43421. public static function loadSystemConfigBlocking()
  43422. {
  43423. if (DIRECTORY_SEPARATOR === '\\') {
  43424. return self::loadWmicBlocking();
  43425. }
  43426. try {
  43427. return self::loadResolvConfBlocking();
  43428. } catch (RuntimeException $ignored) {
  43429. return new self();
  43430. }
  43431. }
  43432. public static function loadResolvConfBlocking($path = null)
  43433. {
  43434. if ($path === null) {
  43435. $path = '/etc/resolv.conf';
  43436. }
  43437. $contents = @file_get_contents($path);
  43438. if ($contents === false) {
  43439. throw new RuntimeException('Unable to load resolv.conf file "' . $path . '"');
  43440. }
  43441. $matches = array();
  43442. preg_match_all('/^nameserver\s+(\S+)\s*$/m', $contents, $matches);
  43443. $config = new self();
  43444. foreach ($matches[1] as $ip) {
  43445. if (strpos($ip, ':') !== false && ($pos = strpos($ip, '%')) !== false) {
  43446. $ip = substr($ip, 0, $pos);
  43447. }
  43448. if (@inet_pton($ip) !== false) {
  43449. $config->nameservers[] = $ip;
  43450. }
  43451. }
  43452. return $config;
  43453. }
  43454. public static function loadWmicBlocking($command = null)
  43455. {
  43456. $contents = shell_exec($command === null ? 'wmic NICCONFIG get "DNSServerSearchOrder" /format:CSV' : $command);
  43457. preg_match_all('/(?<=[{;,"])([\da-f.:]{4,})(?=[};,"])/i', $contents, $matches);
  43458. $config = new self();
  43459. $config->nameservers = $matches[1];
  43460. return $config;
  43461. }
  43462. public $nameservers = array();
  43463. }
  43464. <?php
  43465. namespace React\Dns\Config;
  43466. use RuntimeException;
  43467. class HostsFile
  43468. {
  43469. public static function getDefaultPath()
  43470. {
  43471. if (DIRECTORY_SEPARATOR !== '\\') {
  43472. return '/etc/hosts';
  43473. }
  43474. $path = '%SystemRoot%\\system32\drivers\etc\hosts';
  43475. $base = getenv('SystemRoot');
  43476. if ($base === false) {
  43477. $base = 'C:\\Windows';
  43478. }
  43479. return str_replace('%SystemRoot%', $base, $path);
  43480. }
  43481. public static function loadFromPathBlocking($path = null)
  43482. {
  43483. if ($path === null) {
  43484. $path = self::getDefaultPath();
  43485. }
  43486. $contents = @file_get_contents($path);
  43487. if ($contents === false) {
  43488. throw new RuntimeException('Unable to load hosts file "' . $path . '"');
  43489. }
  43490. return new self($contents);
  43491. }
  43492. private $contents;
  43493. public function __construct($contents)
  43494. {
  43495. $contents = preg_replace('/[ \t]*#.*/', '', strtolower($contents));
  43496. $this->contents = $contents;
  43497. }
  43498. public function getIpsForHost($name)
  43499. {
  43500. $name = strtolower($name);
  43501. $ips = array();
  43502. foreach (preg_split('/\r?\n/', $this->contents) as $line) {
  43503. $parts = preg_split('/\s+/', $line);
  43504. $ip = array_shift($parts);
  43505. if ($parts && array_search($name, $parts) !== false) {
  43506. if (strpos($ip, ':') !== false && ($pos = strpos($ip, '%')) !== false) {
  43507. $ip = substr($ip, 0, $pos);
  43508. }
  43509. if (@inet_pton($ip) !== false) {
  43510. $ips[] = $ip;
  43511. }
  43512. }
  43513. }
  43514. return $ips;
  43515. }
  43516. public function getHostsForIp($ip)
  43517. {
  43518. $ip = @inet_pton($ip);
  43519. if ($ip === false) {
  43520. return array();
  43521. }
  43522. $names = array();
  43523. foreach (preg_split('/\r?\n/', $this->contents) as $line) {
  43524. $parts = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
  43525. $addr = (string) array_shift($parts);
  43526. if (strpos($addr, ':') !== false && ($pos = strpos($addr, '%')) !== false) {
  43527. $addr = substr($addr, 0, $pos);
  43528. }
  43529. if (@inet_pton($addr) === $ip) {
  43530. foreach ($parts as $part) {
  43531. $names[] = $part;
  43532. }
  43533. }
  43534. }
  43535. return $names;
  43536. }
  43537. }
  43538. <?php
  43539. namespace React\Dns\Protocol;
  43540. use React\Dns\Model\Message;
  43541. use React\Dns\Model\Record;
  43542. use React\Dns\Query\Query;
  43543. use InvalidArgumentException;
  43544. final class Parser
  43545. {
  43546. public function parseMessage($data)
  43547. {
  43548. $message = $this->parse($data, 0);
  43549. if ($message === null) {
  43550. throw new InvalidArgumentException('Unable to parse binary message');
  43551. }
  43552. return $message;
  43553. }
  43554. private function parse($data, $consumed)
  43555. {
  43556. if (!isset($data[12 - 1])) {
  43557. return null;
  43558. }
  43559. list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_values(unpack('n*', substr($data, 0, 12)));
  43560. $message = new Message();
  43561. $message->id = $id;
  43562. $message->rcode = $fields & 0xf;
  43563. $message->ra = (($fields >> 7) & 1) === 1;
  43564. $message->rd = (($fields >> 8) & 1) === 1;
  43565. $message->tc = (($fields >> 9) & 1) === 1;
  43566. $message->aa = (($fields >> 10) & 1) === 1;
  43567. $message->opcode = ($fields >> 11) & 0xf;
  43568. $message->qr = (($fields >> 15) & 1) === 1;
  43569. $consumed += 12;
  43570. for ($i = $qdCount; $i > 0; --$i) {
  43571. list($question, $consumed) = $this->parseQuestion($data, $consumed);
  43572. if ($question === null) {
  43573. return null;
  43574. } else {
  43575. $message->questions[] = $question;
  43576. }
  43577. }
  43578. for ($i = $anCount; $i > 0; --$i) {
  43579. list($record, $consumed) = $this->parseRecord($data, $consumed);
  43580. if ($record === null) {
  43581. return null;
  43582. } else {
  43583. $message->answers[] = $record;
  43584. }
  43585. }
  43586. for ($i = $nsCount; $i > 0; --$i) {
  43587. list($record, $consumed) = $this->parseRecord($data, $consumed);
  43588. if ($record === null) {
  43589. return null;
  43590. } else {
  43591. $message->authority[] = $record;
  43592. }
  43593. }
  43594. for ($i = $arCount; $i > 0; --$i) {
  43595. list($record, $consumed) = $this->parseRecord($data, $consumed);
  43596. if ($record === null) {
  43597. return null;
  43598. } else {
  43599. $message->additional[] = $record;
  43600. }
  43601. }
  43602. return $message;
  43603. }
  43604. private function parseQuestion($data, $consumed)
  43605. {
  43606. list($labels, $consumed) = $this->readLabels($data, $consumed);
  43607. if ($labels === null || !isset($data[$consumed + 4 - 1])) {
  43608. return array(null, null);
  43609. }
  43610. list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
  43611. $consumed += 4;
  43612. return array(
  43613. new Query(
  43614. implode('.', $labels),
  43615. $type,
  43616. $class
  43617. ),
  43618. $consumed
  43619. );
  43620. }
  43621. private function parseRecord($data, $consumed)
  43622. {
  43623. list($name, $consumed) = $this->readDomain($data, $consumed);
  43624. if ($name === null || !isset($data[$consumed + 10 - 1])) {
  43625. return array(null, null);
  43626. }
  43627. list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
  43628. $consumed += 4;
  43629. list($ttl) = array_values(unpack('N', substr($data, $consumed, 4)));
  43630. $consumed += 4;
  43631. if ($ttl < 0 || $ttl >= 1 << 31) {
  43632. $ttl = 0;
  43633. }
  43634. list($rdLength) = array_values(unpack('n', substr($data, $consumed, 2)));
  43635. $consumed += 2;
  43636. if (!isset($data[$consumed + $rdLength - 1])) {
  43637. return array(null, null);
  43638. }
  43639. $rdata = null;
  43640. $expected = $consumed + $rdLength;
  43641. if (Message::TYPE_A === $type) {
  43642. if ($rdLength === 4) {
  43643. $rdata = inet_ntop(substr($data, $consumed, $rdLength));
  43644. $consumed += $rdLength;
  43645. }
  43646. } elseif (Message::TYPE_AAAA === $type) {
  43647. if ($rdLength === 16) {
  43648. $rdata = inet_ntop(substr($data, $consumed, $rdLength));
  43649. $consumed += $rdLength;
  43650. }
  43651. } elseif (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type || Message::TYPE_NS === $type) {
  43652. list($rdata, $consumed) = $this->readDomain($data, $consumed);
  43653. } elseif (Message::TYPE_TXT === $type || Message::TYPE_SPF === $type) {
  43654. $rdata = array();
  43655. while ($consumed < $expected) {
  43656. $len = ord($data[$consumed]);
  43657. $rdata[] = (string)substr($data, $consumed + 1, $len);
  43658. $consumed += $len + 1;
  43659. }
  43660. } elseif (Message::TYPE_MX === $type) {
  43661. if ($rdLength > 2) {
  43662. list($priority) = array_values(unpack('n', substr($data, $consumed, 2)));
  43663. list($target, $consumed) = $this->readDomain($data, $consumed + 2);
  43664. $rdata = array(
  43665. 'priority' => $priority,
  43666. 'target' => $target
  43667. );
  43668. }
  43669. } elseif (Message::TYPE_SRV === $type) {
  43670. if ($rdLength > 6) {
  43671. list($priority, $weight, $port) = array_values(unpack('n*', substr($data, $consumed, 6)));
  43672. list($target, $consumed) = $this->readDomain($data, $consumed + 6);
  43673. $rdata = array(
  43674. 'priority' => $priority,
  43675. 'weight' => $weight,
  43676. 'port' => $port,
  43677. 'target' => $target
  43678. );
  43679. }
  43680. } elseif (Message::TYPE_SSHFP === $type) {
  43681. if ($rdLength > 2) {
  43682. list($algorithm, $hash) = \array_values(\unpack('C*', \substr($data, $consumed, 2)));
  43683. $fingerprint = \bin2hex(\substr($data, $consumed + 2, $rdLength - 2));
  43684. $consumed += $rdLength;
  43685. $rdata = array(
  43686. 'algorithm' => $algorithm,
  43687. 'type' => $hash,
  43688. 'fingerprint' => $fingerprint
  43689. );
  43690. }
  43691. } elseif (Message::TYPE_SOA === $type) {
  43692. list($mname, $consumed) = $this->readDomain($data, $consumed);
  43693. list($rname, $consumed) = $this->readDomain($data, $consumed);
  43694. if ($mname !== null && $rname !== null && isset($data[$consumed + 20 - 1])) {
  43695. list($serial, $refresh, $retry, $expire, $minimum) = array_values(unpack('N*', substr($data, $consumed, 20)));
  43696. $consumed += 20;
  43697. $rdata = array(
  43698. 'mname' => $mname,
  43699. 'rname' => $rname,
  43700. 'serial' => $serial,
  43701. 'refresh' => $refresh,
  43702. 'retry' => $retry,
  43703. 'expire' => $expire,
  43704. 'minimum' => $minimum
  43705. );
  43706. }
  43707. } elseif (Message::TYPE_OPT === $type) {
  43708. $rdata = array();
  43709. while (isset($data[$consumed + 4 - 1])) {
  43710. list($code, $length) = array_values(unpack('n*', substr($data, $consumed, 4)));
  43711. $value = (string) substr($data, $consumed + 4, $length);
  43712. if ($code === Message::OPT_TCP_KEEPALIVE && $value === '') {
  43713. $value = null;
  43714. } elseif ($code === Message::OPT_TCP_KEEPALIVE && $length === 2) {
  43715. list($value) = array_values(unpack('n', $value));
  43716. $value = round($value * 0.1, 1);
  43717. } elseif ($code === Message::OPT_TCP_KEEPALIVE) {
  43718. break;
  43719. }
  43720. $rdata[$code] = $value;
  43721. $consumed += 4 + $length;
  43722. }
  43723. } elseif (Message::TYPE_CAA === $type) {
  43724. if ($rdLength > 3) {
  43725. list($flag, $tagLength) = array_values(unpack('C*', substr($data, $consumed, 2)));
  43726. if ($tagLength > 0 && $rdLength - 2 - $tagLength > 0) {
  43727. $tag = substr($data, $consumed + 2, $tagLength);
  43728. $value = substr($data, $consumed + 2 + $tagLength, $rdLength - 2 - $tagLength);
  43729. $consumed += $rdLength;
  43730. $rdata = array(
  43731. 'flag' => $flag,
  43732. 'tag' => $tag,
  43733. 'value' => $value
  43734. );
  43735. }
  43736. }
  43737. } else {
  43738. $rdata = substr($data, $consumed, $rdLength);
  43739. $consumed += $rdLength;
  43740. }
  43741. if ($consumed !== $expected || $rdata === null) {
  43742. return array(null, null);
  43743. }
  43744. return array(
  43745. new Record($name, $type, $class, $ttl, $rdata),
  43746. $consumed
  43747. );
  43748. }
  43749. private function readDomain($data, $consumed)
  43750. {
  43751. list ($labels, $consumed) = $this->readLabels($data, $consumed);
  43752. if ($labels === null) {
  43753. return array(null, null);
  43754. }
  43755. return array(
  43756. \implode(
  43757. '.',
  43758. \array_map(
  43759. function ($label) {
  43760. return \addcslashes($label, "\0..\40.\177");
  43761. },
  43762. $labels
  43763. )
  43764. ),
  43765. $consumed
  43766. );
  43767. }
  43768. private function readLabels($data, $consumed, $compressionDepth = 127)
  43769. {
  43770. $labels = array();
  43771. while (true) {
  43772. if (!isset($data[$consumed])) {
  43773. return array(null, null);
  43774. }
  43775. $length = \ord($data[$consumed]);
  43776. if ($length === 0) {
  43777. $consumed += 1;
  43778. break;
  43779. }
  43780. if (($length & 0xc0) === 0xc0 && isset($data[$consumed + 1]) && $compressionDepth) {
  43781. $offset = ($length & ~0xc0) << 8 | \ord($data[$consumed + 1]);
  43782. if ($offset >= $consumed) {
  43783. return array(null, null);
  43784. }
  43785. $consumed += 2;
  43786. list($newLabels) = $this->readLabels($data, $offset, $compressionDepth - 1);
  43787. if ($newLabels === null) {
  43788. return array(null, null);
  43789. }
  43790. $labels = array_merge($labels, $newLabels);
  43791. break;
  43792. }
  43793. if ($length & 0xc0 || !isset($data[$consumed + $length - 1])) {
  43794. return array(null, null);
  43795. }
  43796. $labels[] = substr($data, $consumed + 1, $length);
  43797. $consumed += $length + 1;
  43798. }
  43799. return array($labels, $consumed);
  43800. }
  43801. }
  43802. <?php
  43803. namespace React\Dns\Protocol;
  43804. use React\Dns\Model\Message;
  43805. use React\Dns\Model\Record;
  43806. use React\Dns\Query\Query;
  43807. final class BinaryDumper
  43808. {
  43809. public function toBinary(Message $message)
  43810. {
  43811. $data = '';
  43812. $data .= $this->headerToBinary($message);
  43813. $data .= $this->questionToBinary($message->questions);
  43814. $data .= $this->recordsToBinary($message->answers);
  43815. $data .= $this->recordsToBinary($message->authority);
  43816. $data .= $this->recordsToBinary($message->additional);
  43817. return $data;
  43818. }
  43819. private function headerToBinary(Message $message)
  43820. {
  43821. $data = '';
  43822. $data .= pack('n', $message->id);
  43823. $flags = 0x00;
  43824. $flags = ($flags << 1) | ($message->qr ? 1 : 0);
  43825. $flags = ($flags << 4) | $message->opcode;
  43826. $flags = ($flags << 1) | ($message->aa ? 1 : 0);
  43827. $flags = ($flags << 1) | ($message->tc ? 1 : 0);
  43828. $flags = ($flags << 1) | ($message->rd ? 1 : 0);
  43829. $flags = ($flags << 1) | ($message->ra ? 1 : 0);
  43830. $flags = ($flags << 3) | 0;
  43831. $flags = ($flags << 4) | $message->rcode;
  43832. $data .= pack('n', $flags);
  43833. $data .= pack('n', count($message->questions));
  43834. $data .= pack('n', count($message->answers));
  43835. $data .= pack('n', count($message->authority));
  43836. $data .= pack('n', count($message->additional));
  43837. return $data;
  43838. }
  43839. private function questionToBinary(array $questions)
  43840. {
  43841. $data = '';
  43842. foreach ($questions as $question) {
  43843. $data .= $this->domainNameToBinary($question->name);
  43844. $data .= pack('n*', $question->type, $question->class);
  43845. }
  43846. return $data;
  43847. }
  43848. private function recordsToBinary(array $records)
  43849. {
  43850. $data = '';
  43851. foreach ($records as $record) {
  43852. switch ($record->type) {
  43853. case Message::TYPE_A:
  43854. case Message::TYPE_AAAA:
  43855. $binary = \inet_pton($record->data);
  43856. break;
  43857. case Message::TYPE_CNAME:
  43858. case Message::TYPE_NS:
  43859. case Message::TYPE_PTR:
  43860. $binary = $this->domainNameToBinary($record->data);
  43861. break;
  43862. case Message::TYPE_TXT:
  43863. case Message::TYPE_SPF:
  43864. $binary = $this->textsToBinary($record->data);
  43865. break;
  43866. case Message::TYPE_MX:
  43867. $binary = \pack(
  43868. 'n',
  43869. $record->data['priority']
  43870. );
  43871. $binary .= $this->domainNameToBinary($record->data['target']);
  43872. break;
  43873. case Message::TYPE_SRV:
  43874. $binary = \pack(
  43875. 'n*',
  43876. $record->data['priority'],
  43877. $record->data['weight'],
  43878. $record->data['port']
  43879. );
  43880. $binary .= $this->domainNameToBinary($record->data['target']);
  43881. break;
  43882. case Message::TYPE_SOA:
  43883. $binary = $this->domainNameToBinary($record->data['mname']);
  43884. $binary .= $this->domainNameToBinary($record->data['rname']);
  43885. $binary .= \pack(
  43886. 'N*',
  43887. $record->data['serial'],
  43888. $record->data['refresh'],
  43889. $record->data['retry'],
  43890. $record->data['expire'],
  43891. $record->data['minimum']
  43892. );
  43893. break;
  43894. case Message::TYPE_CAA:
  43895. $binary = \pack(
  43896. 'C*',
  43897. $record->data['flag'],
  43898. \strlen($record->data['tag'])
  43899. );
  43900. $binary .= $record->data['tag'];
  43901. $binary .= $record->data['value'];
  43902. break;
  43903. case Message::TYPE_SSHFP:
  43904. $binary = \pack(
  43905. 'CCH*',
  43906. $record->data['algorithm'],
  43907. $record->data['type'],
  43908. $record->data['fingerprint']
  43909. );
  43910. break;
  43911. case Message::TYPE_OPT:
  43912. $binary = '';
  43913. foreach ($record->data as $opt => $value) {
  43914. if ($opt === Message::OPT_TCP_KEEPALIVE && $value !== null) {
  43915. $value = \pack('n', round($value * 10));
  43916. }
  43917. $binary .= \pack('n*', $opt, \strlen((string) $value)) . $value;
  43918. }
  43919. break;
  43920. default:
  43921. $binary = $record->data;
  43922. }
  43923. $data .= $this->domainNameToBinary($record->name);
  43924. $data .= \pack('nnNn', $record->type, $record->class, $record->ttl, \strlen($binary));
  43925. $data .= $binary;
  43926. }
  43927. return $data;
  43928. }
  43929. private function textsToBinary(array $texts)
  43930. {
  43931. $data = '';
  43932. foreach ($texts as $text) {
  43933. $data .= \chr(\strlen($text)) . $text;
  43934. }
  43935. return $data;
  43936. }
  43937. private function domainNameToBinary($host)
  43938. {
  43939. if ($host === '') {
  43940. return "\0";
  43941. }
  43942. return $this->textsToBinary(
  43943. \array_map(
  43944. 'stripcslashes',
  43945. \preg_split(
  43946. '/(?<!\\\\)\./',
  43947. $host . '.'
  43948. )
  43949. )
  43950. );
  43951. }
  43952. }
  43953. <?php
  43954. namespace React\Dns\Model;
  43955. final class Record
  43956. {
  43957. public $name;
  43958. public $type;
  43959. public $class;
  43960. public $ttl;
  43961. public $data;
  43962. public function __construct($name, $type, $class, $ttl, $data)
  43963. {
  43964. $this->name = $name;
  43965. $this->type = $type;
  43966. $this->class = $class;
  43967. $this->ttl = $ttl;
  43968. $this->data = $data;
  43969. }
  43970. }
  43971. <?php
  43972. namespace React\Dns\Model;
  43973. use React\Dns\Query\Query;
  43974. final class Message
  43975. {
  43976. const TYPE_A = 1;
  43977. const TYPE_NS = 2;
  43978. const TYPE_CNAME = 5;
  43979. const TYPE_SOA = 6;
  43980. const TYPE_PTR = 12;
  43981. const TYPE_MX = 15;
  43982. const TYPE_TXT = 16;
  43983. const TYPE_AAAA = 28;
  43984. const TYPE_SRV = 33;
  43985. const TYPE_SSHFP = 44;
  43986. const TYPE_OPT = 41;
  43987. const TYPE_SPF = 99;
  43988. const TYPE_ANY = 255;
  43989. const TYPE_CAA = 257;
  43990. const CLASS_IN = 1;
  43991. const OPCODE_QUERY = 0;
  43992. const OPCODE_IQUERY = 1;
  43993. const OPCODE_STATUS = 2;
  43994. const RCODE_OK = 0;
  43995. const RCODE_FORMAT_ERROR = 1;
  43996. const RCODE_SERVER_FAILURE = 2;
  43997. const RCODE_NAME_ERROR = 3;
  43998. const RCODE_NOT_IMPLEMENTED = 4;
  43999. const RCODE_REFUSED = 5;
  44000. const OPT_TCP_KEEPALIVE = 11;
  44001. const OPT_PADDING = 12;
  44002. public static function createRequestForQuery(Query $query)
  44003. {
  44004. $request = new Message();
  44005. $request->id = self::generateId();
  44006. $request->rd = true;
  44007. $request->questions[] = $query;
  44008. return $request;
  44009. }
  44010. public static function createResponseWithAnswersForQuery(Query $query, array $answers)
  44011. {
  44012. $response = new Message();
  44013. $response->id = self::generateId();
  44014. $response->qr = true;
  44015. $response->rd = true;
  44016. $response->questions[] = $query;
  44017. foreach ($answers as $record) {
  44018. $response->answers[] = $record;
  44019. }
  44020. return $response;
  44021. }
  44022. private static function generateId()
  44023. {
  44024. if (function_exists('random_int')) {
  44025. return random_int(0, 0xffff);
  44026. }
  44027. return mt_rand(0, 0xffff);
  44028. }
  44029. public $id = 0;
  44030. public $qr = false;
  44031. public $opcode = self::OPCODE_QUERY;
  44032. public $aa = false;
  44033. public $tc = false;
  44034. public $rd = false;
  44035. public $ra = false;
  44036. public $rcode = Message::RCODE_OK;
  44037. public $questions = array();
  44038. public $answers = array();
  44039. public $authority = array();
  44040. public $additional = array();
  44041. }
  44042. <?php
  44043. namespace React\Dns\Query;
  44044. use React\Dns\Config\HostsFile;
  44045. use React\Dns\Model\Message;
  44046. use React\Dns\Model\Record;
  44047. use React\Promise;
  44048. final class HostsFileExecutor implements ExecutorInterface
  44049. {
  44050. private $hosts;
  44051. private $fallback;
  44052. public function __construct(HostsFile $hosts, ExecutorInterface $fallback)
  44053. {
  44054. $this->hosts = $hosts;
  44055. $this->fallback = $fallback;
  44056. }
  44057. public function query(Query $query)
  44058. {
  44059. if ($query->class === Message::CLASS_IN && ($query->type === Message::TYPE_A || $query->type === Message::TYPE_AAAA)) {
  44060. $records = array();
  44061. $expectsColon = $query->type === Message::TYPE_AAAA;
  44062. foreach ($this->hosts->getIpsForHost($query->name) as $ip) {
  44063. if ((strpos($ip, ':') !== false) === $expectsColon) {
  44064. $records[] = new Record($query->name, $query->type, $query->class, 0, $ip);
  44065. }
  44066. }
  44067. if ($records) {
  44068. return Promise\resolve(
  44069. Message::createResponseWithAnswersForQuery($query, $records)
  44070. );
  44071. }
  44072. } elseif ($query->class === Message::CLASS_IN && $query->type === Message::TYPE_PTR) {
  44073. $ip = $this->getIpFromHost($query->name);
  44074. if ($ip !== null) {
  44075. $records = array();
  44076. foreach ($this->hosts->getHostsForIp($ip) as $host) {
  44077. $records[] = new Record($query->name, $query->type, $query->class, 0, $host);
  44078. }
  44079. if ($records) {
  44080. return Promise\resolve(
  44081. Message::createResponseWithAnswersForQuery($query, $records)
  44082. );
  44083. }
  44084. }
  44085. }
  44086. return $this->fallback->query($query);
  44087. }
  44088. private function getIpFromHost($host)
  44089. {
  44090. if (substr($host, -13) === '.in-addr.arpa') {
  44091. $ip = @inet_pton(substr($host, 0, -13));
  44092. if ($ip === false || isset($ip[4])) {
  44093. return null;
  44094. }
  44095. return inet_ntop(strrev($ip));
  44096. } elseif (substr($host, -9) === '.ip6.arpa') {
  44097. $ip = @inet_ntop(pack('H*', strrev(str_replace('.', '', substr($host, 0, -9)))));
  44098. if ($ip === false) {
  44099. return null;
  44100. }
  44101. return $ip;
  44102. } else {
  44103. return null;
  44104. }
  44105. }
  44106. }
  44107. <?php
  44108. namespace React\Dns\Query;
  44109. final class CancellationException extends \RuntimeException
  44110. {
  44111. }
  44112. <?php
  44113. namespace React\Dns\Query;
  44114. use React\Dns\Model\Message;
  44115. use React\Dns\Protocol\BinaryDumper;
  44116. use React\Dns\Protocol\Parser;
  44117. use React\EventLoop\Loop;
  44118. use React\EventLoop\LoopInterface;
  44119. use React\Promise\Deferred;
  44120. class TcpTransportExecutor implements ExecutorInterface
  44121. {
  44122. private $nameserver;
  44123. private $loop;
  44124. private $parser;
  44125. private $dumper;
  44126. private $socket;
  44127. private $pending = array();
  44128. private $names = array();
  44129. private $idlePeriod = 0.001;
  44130. private $idleTimer;
  44131. private $writeBuffer = '';
  44132. private $writePending = false;
  44133. private $readBuffer = '';
  44134. private $readPending = false;
  44135. private $readChunk = 0xffff;
  44136. public function __construct($nameserver, $loop = null)
  44137. {
  44138. if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) {
  44139. $nameserver = '[' . $nameserver . ']';
  44140. }
  44141. $parts = \parse_url((\strpos($nameserver, '://') === false ? 'tcp://' : '') . $nameserver);
  44142. if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'tcp' || @\inet_pton(\trim($parts['host'], '[]')) === false) {
  44143. throw new \InvalidArgumentException('Invalid nameserver address given');
  44144. }
  44145. if ($loop !== null && !$loop instanceof LoopInterface) {
  44146. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  44147. }
  44148. $this->nameserver = 'tcp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53);
  44149. $this->loop = $loop ?: Loop::get();
  44150. $this->parser = new Parser();
  44151. $this->dumper = new BinaryDumper();
  44152. }
  44153. public function query(Query $query)
  44154. {
  44155. $request = Message::createRequestForQuery($query);
  44156. while (isset($this->pending[$request->id])) {
  44157. $request->id = \mt_rand(0, 0xffff);
  44158. }
  44159. $queryData = $this->dumper->toBinary($request);
  44160. $length = \strlen($queryData);
  44161. if ($length > 0xffff) {
  44162. return \React\Promise\reject(new \RuntimeException(
  44163. 'DNS query for ' . $query->describe() . ' failed: Query too large for TCP transport'
  44164. ));
  44165. }
  44166. $queryData = \pack('n', $length) . $queryData;
  44167. if ($this->socket === null) {
  44168. $socket = @\stream_socket_client($this->nameserver, $errno, $errstr, 0, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT);
  44169. if ($socket === false) {
  44170. return \React\Promise\reject(new \RuntimeException(
  44171. 'DNS query for ' . $query->describe() . ' failed: Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
  44172. $errno
  44173. ));
  44174. }
  44175. \stream_set_blocking($socket, false);
  44176. if (\function_exists('stream_set_chunk_size')) {
  44177. \stream_set_chunk_size($socket, $this->readChunk);
  44178. }
  44179. $this->socket = $socket;
  44180. }
  44181. if ($this->idleTimer !== null) {
  44182. $this->loop->cancelTimer($this->idleTimer);
  44183. $this->idleTimer = null;
  44184. }
  44185. $this->writeBuffer .= $queryData;
  44186. if (!$this->writePending) {
  44187. $this->writePending = true;
  44188. $this->loop->addWriteStream($this->socket, array($this, 'handleWritable'));
  44189. }
  44190. $names =& $this->names;
  44191. $that = $this;
  44192. $deferred = new Deferred(function () use ($that, &$names, $request) {
  44193. $name = $names[$request->id];
  44194. unset($names[$request->id]);
  44195. $that->checkIdle();
  44196. throw new CancellationException('DNS query for ' . $name . ' has been cancelled');
  44197. });
  44198. $this->pending[$request->id] = $deferred;
  44199. $this->names[$request->id] = $query->describe();
  44200. return $deferred->promise();
  44201. }
  44202. public function handleWritable()
  44203. {
  44204. if ($this->readPending === false) {
  44205. $name = @\stream_socket_get_name($this->socket, true);
  44206. if ($name === false) {
  44207. if (\function_exists('socket_import_stream')) {
  44208. $socket = \socket_import_stream($this->socket);
  44209. $errno = \socket_get_option($socket, \SOL_SOCKET, \SO_ERROR);
  44210. $errstr = \socket_strerror($errno);
  44211. } else {
  44212. $errno = \defined('SOCKET_ECONNREFUSED') ? \SOCKET_ECONNREFUSED : 111;
  44213. $errstr = 'Connection refused';
  44214. }
  44215. $this->closeError('Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')', $errno);
  44216. return;
  44217. }
  44218. $this->readPending = true;
  44219. $this->loop->addReadStream($this->socket, array($this, 'handleRead'));
  44220. }
  44221. $errno = 0;
  44222. $errstr = '';
  44223. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  44224. \preg_match('/errno=(\d+) (.+)/', $error, $m);
  44225. $errno = isset($m[1]) ? (int) $m[1] : 0;
  44226. $errstr = isset($m[2]) ? $m[2] : $error;
  44227. });
  44228. $written = \fwrite($this->socket, $this->writeBuffer);
  44229. \restore_error_handler();
  44230. if ($written === false || $written === 0) {
  44231. $this->closeError(
  44232. 'Unable to send query to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
  44233. $errno
  44234. );
  44235. return;
  44236. }
  44237. if (isset($this->writeBuffer[$written])) {
  44238. $this->writeBuffer = \substr($this->writeBuffer, $written);
  44239. } else {
  44240. $this->loop->removeWriteStream($this->socket);
  44241. $this->writePending = false;
  44242. $this->writeBuffer = '';
  44243. }
  44244. }
  44245. public function handleRead()
  44246. {
  44247. $chunk = @\fread($this->socket, $this->readChunk);
  44248. if ($chunk === false || $chunk === '') {
  44249. $this->closeError('Connection to DNS server ' . $this->nameserver . ' lost');
  44250. return;
  44251. }
  44252. $this->readBuffer .= $chunk;
  44253. while (isset($this->readBuffer[11])) {
  44254. list(, $length) = \unpack('n', $this->readBuffer);
  44255. if (!isset($this->readBuffer[$length + 1])) {
  44256. return;
  44257. }
  44258. $data = \substr($this->readBuffer, 2, $length);
  44259. $this->readBuffer = (string)substr($this->readBuffer, $length + 2);
  44260. try {
  44261. $response = $this->parser->parseMessage($data);
  44262. } catch (\Exception $e) {
  44263. $this->closeError('Invalid message received from DNS server ' . $this->nameserver);
  44264. return;
  44265. }
  44266. if (!isset($this->pending[$response->id]) || $response->tc) {
  44267. $this->closeError('Invalid response message received from DNS server ' . $this->nameserver);
  44268. return;
  44269. }
  44270. $deferred = $this->pending[$response->id];
  44271. unset($this->pending[$response->id], $this->names[$response->id]);
  44272. $deferred->resolve($response);
  44273. $this->checkIdle();
  44274. }
  44275. }
  44276. public function closeError($reason, $code = 0)
  44277. {
  44278. $this->readBuffer = '';
  44279. if ($this->readPending) {
  44280. $this->loop->removeReadStream($this->socket);
  44281. $this->readPending = false;
  44282. }
  44283. $this->writeBuffer = '';
  44284. if ($this->writePending) {
  44285. $this->loop->removeWriteStream($this->socket);
  44286. $this->writePending = false;
  44287. }
  44288. if ($this->idleTimer !== null) {
  44289. $this->loop->cancelTimer($this->idleTimer);
  44290. $this->idleTimer = null;
  44291. }
  44292. @\fclose($this->socket);
  44293. $this->socket = null;
  44294. foreach ($this->names as $id => $name) {
  44295. $this->pending[$id]->reject(new \RuntimeException(
  44296. 'DNS query for ' . $name . ' failed: ' . $reason,
  44297. $code
  44298. ));
  44299. }
  44300. $this->pending = $this->names = array();
  44301. }
  44302. public function checkIdle()
  44303. {
  44304. if ($this->idleTimer === null && !$this->names) {
  44305. $that = $this;
  44306. $this->idleTimer = $this->loop->addTimer($this->idlePeriod, function () use ($that) {
  44307. $that->closeError('Idle timeout');
  44308. });
  44309. }
  44310. }
  44311. }
  44312. <?php
  44313. namespace React\Dns\Query;
  44314. use React\Promise\Promise;
  44315. final class CoopExecutor implements ExecutorInterface
  44316. {
  44317. private $executor;
  44318. private $pending = array();
  44319. private $counts = array();
  44320. public function __construct(ExecutorInterface $base)
  44321. {
  44322. $this->executor = $base;
  44323. }
  44324. public function query(Query $query)
  44325. {
  44326. $key = $this->serializeQueryToIdentity($query);
  44327. if (isset($this->pending[$key])) {
  44328. $promise = $this->pending[$key];
  44329. ++$this->counts[$key];
  44330. } else {
  44331. $promise = $this->executor->query($query);
  44332. $this->pending[$key] = $promise;
  44333. $this->counts[$key] = 1;
  44334. $pending =& $this->pending;
  44335. $counts =& $this->counts;
  44336. $promise->then(function () use ($key, &$pending, &$counts) {
  44337. unset($pending[$key], $counts[$key]);
  44338. }, function () use ($key, &$pending, &$counts) {
  44339. unset($pending[$key], $counts[$key]);
  44340. });
  44341. }
  44342. $pending =& $this->pending;
  44343. $counts =& $this->counts;
  44344. return new Promise(function ($resolve, $reject) use ($promise) {
  44345. $promise->then($resolve, $reject);
  44346. }, function () use (&$promise, $key, $query, &$pending, &$counts) {
  44347. if (--$counts[$key] < 1) {
  44348. unset($pending[$key], $counts[$key]);
  44349. $promise->cancel();
  44350. $promise = null;
  44351. }
  44352. throw new \RuntimeException('DNS query for ' . $query->describe() . ' has been cancelled');
  44353. });
  44354. }
  44355. private function serializeQueryToIdentity(Query $query)
  44356. {
  44357. return sprintf('%s:%s:%s', $query->name, $query->type, $query->class);
  44358. }
  44359. }
  44360. <?php
  44361. namespace React\Dns\Query;
  44362. interface ExecutorInterface
  44363. {
  44364. public function query(Query $query);
  44365. }
  44366. <?php
  44367. namespace React\Dns\Query;
  44368. use React\Promise\Promise;
  44369. class SelectiveTransportExecutor implements ExecutorInterface
  44370. {
  44371. private $datagramExecutor;
  44372. private $streamExecutor;
  44373. public function __construct(ExecutorInterface $datagramExecutor, ExecutorInterface $streamExecutor)
  44374. {
  44375. $this->datagramExecutor = $datagramExecutor;
  44376. $this->streamExecutor = $streamExecutor;
  44377. }
  44378. public function query(Query $query)
  44379. {
  44380. $stream = $this->streamExecutor;
  44381. $pending = $this->datagramExecutor->query($query);
  44382. return new Promise(function ($resolve, $reject) use (&$pending, $stream, $query) {
  44383. $pending->then(
  44384. $resolve,
  44385. function ($e) use (&$pending, $stream, $query, $resolve, $reject) {
  44386. if ($e->getCode() === (\defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90)) {
  44387. $pending = $stream->query($query)->then($resolve, $reject);
  44388. } else {
  44389. $reject($e);
  44390. }
  44391. }
  44392. );
  44393. }, function () use (&$pending) {
  44394. $pending->cancel();
  44395. $pending = null;
  44396. });
  44397. }
  44398. }
  44399. <?php
  44400. namespace React\Dns\Query;
  44401. use React\Promise\Promise;
  44402. final class FallbackExecutor implements ExecutorInterface
  44403. {
  44404. private $executor;
  44405. private $fallback;
  44406. public function __construct(ExecutorInterface $executor, ExecutorInterface $fallback)
  44407. {
  44408. $this->executor = $executor;
  44409. $this->fallback = $fallback;
  44410. }
  44411. public function query(Query $query)
  44412. {
  44413. $cancelled = false;
  44414. $fallback = $this->fallback;
  44415. $promise = $this->executor->query($query);
  44416. return new Promise(function ($resolve, $reject) use (&$promise, $fallback, $query, &$cancelled) {
  44417. $promise->then($resolve, function (\Exception $e1) use ($fallback, $query, $resolve, $reject, &$cancelled, &$promise) {
  44418. if ($cancelled) {
  44419. $reject($e1);
  44420. return;
  44421. }
  44422. $promise = $fallback->query($query)->then($resolve, function (\Exception $e2) use ($e1, $reject) {
  44423. $append = $e2->getMessage();
  44424. if (($pos = strpos($append, ':')) !== false) {
  44425. $append = substr($append, $pos + 2);
  44426. }
  44427. $reject(new \RuntimeException($e1->getMessage() . '. ' . $append));
  44428. });
  44429. });
  44430. }, function () use (&$promise, &$cancelled) {
  44431. $cancelled = true;
  44432. $promise->cancel();
  44433. });
  44434. }
  44435. }
  44436. <?php
  44437. namespace React\Dns\Query;
  44438. use React\Dns\Model\Message;
  44439. use React\Dns\Protocol\BinaryDumper;
  44440. use React\Dns\Protocol\Parser;
  44441. use React\EventLoop\Loop;
  44442. use React\EventLoop\LoopInterface;
  44443. use React\Promise\Deferred;
  44444. final class UdpTransportExecutor implements ExecutorInterface
  44445. {
  44446. private $nameserver;
  44447. private $loop;
  44448. private $parser;
  44449. private $dumper;
  44450. private $maxPacketSize = 512;
  44451. public function __construct($nameserver, $loop = null)
  44452. {
  44453. if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) {
  44454. $nameserver = '[' . $nameserver . ']';
  44455. }
  44456. $parts = \parse_url((\strpos($nameserver, '://') === false ? 'udp://' : '') . $nameserver);
  44457. if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'udp' || @\inet_pton(\trim($parts['host'], '[]')) === false) {
  44458. throw new \InvalidArgumentException('Invalid nameserver address given');
  44459. }
  44460. if ($loop !== null && !$loop instanceof LoopInterface) {
  44461. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  44462. }
  44463. $this->nameserver = 'udp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53);
  44464. $this->loop = $loop ?: Loop::get();
  44465. $this->parser = new Parser();
  44466. $this->dumper = new BinaryDumper();
  44467. }
  44468. public function query(Query $query)
  44469. {
  44470. $request = Message::createRequestForQuery($query);
  44471. $queryData = $this->dumper->toBinary($request);
  44472. if (isset($queryData[$this->maxPacketSize])) {
  44473. return \React\Promise\reject(new \RuntimeException(
  44474. 'DNS query for ' . $query->describe() . ' failed: Query too large for UDP transport',
  44475. \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90
  44476. ));
  44477. }
  44478. $errno = 0;
  44479. $errstr = '';
  44480. $socket = @\stream_socket_client($this->nameserver, $errno, $errstr, 0);
  44481. if ($socket === false) {
  44482. return \React\Promise\reject(new \RuntimeException(
  44483. 'DNS query for ' . $query->describe() . ' failed: Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
  44484. $errno
  44485. ));
  44486. }
  44487. \stream_set_blocking($socket, false);
  44488. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  44489. \preg_match('/errno=(\d+) (.+)/', $error, $m);
  44490. $errno = isset($m[1]) ? (int) $m[1] : 0;
  44491. $errstr = isset($m[2]) ? $m[2] : $error;
  44492. });
  44493. $written = \fwrite($socket, $queryData);
  44494. \restore_error_handler();
  44495. if ($written !== \strlen($queryData)) {
  44496. return \React\Promise\reject(new \RuntimeException(
  44497. 'DNS query for ' . $query->describe() . ' failed: Unable to send query to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
  44498. $errno
  44499. ));
  44500. }
  44501. $loop = $this->loop;
  44502. $deferred = new Deferred(function () use ($loop, $socket, $query) {
  44503. $loop->removeReadStream($socket);
  44504. \fclose($socket);
  44505. throw new CancellationException('DNS query for ' . $query->describe() . ' has been cancelled');
  44506. });
  44507. $max = $this->maxPacketSize;
  44508. $parser = $this->parser;
  44509. $nameserver = $this->nameserver;
  44510. $loop->addReadStream($socket, function ($socket) use ($loop, $deferred, $query, $parser, $request, $max, $nameserver) {
  44511. $data = @\fread($socket, $max);
  44512. if ($data === false) {
  44513. return;
  44514. }
  44515. try {
  44516. $response = $parser->parseMessage($data);
  44517. } catch (\Exception $e) {
  44518. return;
  44519. }
  44520. if ($response->id !== $request->id) {
  44521. return;
  44522. }
  44523. $loop->removeReadStream($socket);
  44524. \fclose($socket);
  44525. if ($response->tc) {
  44526. $deferred->reject(new \RuntimeException(
  44527. 'DNS query for ' . $query->describe() . ' failed: The DNS server ' . $nameserver . ' returned a truncated result for a UDP query',
  44528. \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90
  44529. ));
  44530. return;
  44531. }
  44532. $deferred->resolve($response);
  44533. });
  44534. return $deferred->promise();
  44535. }
  44536. }
  44537. <?php
  44538. namespace React\Dns\Query;
  44539. use React\Promise\Deferred;
  44540. use React\Promise\PromiseInterface;
  44541. final class RetryExecutor implements ExecutorInterface
  44542. {
  44543. private $executor;
  44544. private $retries;
  44545. public function __construct(ExecutorInterface $executor, $retries = 2)
  44546. {
  44547. $this->executor = $executor;
  44548. $this->retries = $retries;
  44549. }
  44550. public function query(Query $query)
  44551. {
  44552. return $this->tryQuery($query, $this->retries);
  44553. }
  44554. public function tryQuery(Query $query, $retries)
  44555. {
  44556. $deferred = new Deferred(function () use (&$promise) {
  44557. if ($promise instanceof PromiseInterface && \method_exists($promise, 'cancel')) {
  44558. $promise->cancel();
  44559. }
  44560. });
  44561. $success = function ($value) use ($deferred, &$errorback) {
  44562. $errorback = null;
  44563. $deferred->resolve($value);
  44564. };
  44565. $executor = $this->executor;
  44566. $errorback = function ($e) use ($deferred, &$promise, $query, $success, &$errorback, &$retries, $executor) {
  44567. if (!$e instanceof TimeoutException) {
  44568. $errorback = null;
  44569. $deferred->reject($e);
  44570. } elseif ($retries <= 0) {
  44571. $errorback = null;
  44572. $deferred->reject($e = new \RuntimeException(
  44573. 'DNS query for ' . $query->describe() . ' failed: too many retries',
  44574. 0,
  44575. $e
  44576. ));
  44577. $r = new \ReflectionProperty('Exception', 'trace');
  44578. $r->setAccessible(true);
  44579. $trace = $r->getValue($e);
  44580. foreach ($trace as $ti => $one) {
  44581. if (isset($one['args'])) {
  44582. foreach ($one['args'] as $ai => $arg) {
  44583. if ($arg instanceof \Closure) {
  44584. $trace[$ti]['args'][$ai] = 'Object(' . \get_class($arg) . ')';
  44585. }
  44586. }
  44587. }
  44588. }
  44589. $r->setValue($e, $trace);
  44590. } else {
  44591. --$retries;
  44592. $promise = $executor->query($query)->then(
  44593. $success,
  44594. $errorback
  44595. );
  44596. }
  44597. };
  44598. $promise = $this->executor->query($query)->then(
  44599. $success,
  44600. $errorback
  44601. );
  44602. return $deferred->promise();
  44603. }
  44604. }
  44605. <?php
  44606. namespace React\Dns\Query;
  44607. use React\Dns\Model\Message;
  44608. final class Query
  44609. {
  44610. public $name;
  44611. public $type;
  44612. public $class;
  44613. public function __construct($name, $type, $class)
  44614. {
  44615. $this->name = $name;
  44616. $this->type = $type;
  44617. $this->class = $class;
  44618. }
  44619. public function describe()
  44620. {
  44621. $class = $this->class !== Message::CLASS_IN ? 'CLASS' . $this->class . ' ' : '';
  44622. $type = 'TYPE' . $this->type;
  44623. $ref = new \ReflectionClass('React\Dns\Model\Message');
  44624. foreach ($ref->getConstants() as $name => $value) {
  44625. if ($value === $this->type && \strpos($name, 'TYPE_') === 0) {
  44626. $type = \substr($name, 5);
  44627. break;
  44628. }
  44629. }
  44630. return $this->name . ' (' . $class . $type . ')';
  44631. }
  44632. }
  44633. <?php
  44634. namespace React\Dns\Query;
  44635. use React\EventLoop\Loop;
  44636. use React\EventLoop\LoopInterface;
  44637. use React\Promise\Promise;
  44638. final class TimeoutExecutor implements ExecutorInterface
  44639. {
  44640. private $executor;
  44641. private $loop;
  44642. private $timeout;
  44643. public function __construct(ExecutorInterface $executor, $timeout, $loop = null)
  44644. {
  44645. if ($loop !== null && !$loop instanceof LoopInterface) {
  44646. throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
  44647. }
  44648. $this->executor = $executor;
  44649. $this->loop = $loop ?: Loop::get();
  44650. $this->timeout = $timeout;
  44651. }
  44652. public function query(Query $query)
  44653. {
  44654. $promise = $this->executor->query($query);
  44655. $loop = $this->loop;
  44656. $time = $this->timeout;
  44657. return new Promise(function ($resolve, $reject) use ($loop, $time, $promise, $query) {
  44658. $timer = null;
  44659. $promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
  44660. if ($timer) {
  44661. $loop->cancelTimer($timer);
  44662. }
  44663. $timer = false;
  44664. $resolve($v);
  44665. }, function ($v) use (&$timer, $loop, $reject) {
  44666. if ($timer) {
  44667. $loop->cancelTimer($timer);
  44668. }
  44669. $timer = false;
  44670. $reject($v);
  44671. });
  44672. if ($timer === false) {
  44673. return;
  44674. }
  44675. $timer = $loop->addTimer($time, function () use ($time, &$promise, $reject, $query) {
  44676. $reject(new TimeoutException(
  44677. 'DNS query for ' . $query->describe() . ' timed out'
  44678. ));
  44679. assert(\method_exists($promise, 'cancel'));
  44680. $promise->cancel();
  44681. $promise = null;
  44682. });
  44683. }, function () use (&$promise) {
  44684. assert(\method_exists($promise, 'cancel'));
  44685. $promise->cancel();
  44686. $promise = null;
  44687. });
  44688. }
  44689. }
  44690. <?php
  44691. namespace React\Dns\Query;
  44692. final class TimeoutException extends \Exception
  44693. {
  44694. }
  44695. <?php
  44696. namespace React\Dns\Query;
  44697. use React\Cache\CacheInterface;
  44698. use React\Dns\Model\Message;
  44699. use React\Promise\Promise;
  44700. final class CachingExecutor implements ExecutorInterface
  44701. {
  44702. const TTL = 60;
  44703. private $executor;
  44704. private $cache;
  44705. public function __construct(ExecutorInterface $executor, CacheInterface $cache)
  44706. {
  44707. $this->executor = $executor;
  44708. $this->cache = $cache;
  44709. }
  44710. public function query(Query $query)
  44711. {
  44712. $id = $query->name . ':' . $query->type . ':' . $query->class;
  44713. $cache = $this->cache;
  44714. $that = $this;
  44715. $executor = $this->executor;
  44716. $pending = $cache->get($id);
  44717. return new Promise(function ($resolve, $reject) use ($query, $id, $cache, $executor, &$pending, $that) {
  44718. $pending->then(
  44719. function ($message) use ($query, $id, $cache, $executor, &$pending, $that) {
  44720. if ($message !== null) {
  44721. return $message;
  44722. }
  44723. return $pending = $executor->query($query)->then(
  44724. function (Message $message) use ($cache, $id, $that) {
  44725. if (!$message->tc) {
  44726. $cache->set($id, $message, $that->ttl($message));
  44727. }
  44728. return $message;
  44729. }
  44730. );
  44731. }
  44732. )->then($resolve, function ($e) use ($reject, &$pending) {
  44733. $reject($e);
  44734. $pending = null;
  44735. });
  44736. }, function ($_, $reject) use (&$pending, $query) {
  44737. $reject(new \RuntimeException('DNS query for ' . $query->describe() . ' has been cancelled'));
  44738. $pending->cancel();
  44739. $pending = null;
  44740. });
  44741. }
  44742. public function ttl(Message $message)
  44743. {
  44744. $ttl = null;
  44745. foreach ($message->answers as $answer) {
  44746. if ($ttl === null || $answer->ttl < $ttl) {
  44747. $ttl = $answer->ttl;
  44748. }
  44749. }
  44750. if ($ttl === null) {
  44751. $ttl = self::TTL;
  44752. }
  44753. return $ttl;
  44754. }
  44755. }
  44756. <?php
  44757. namespace React\Dns\Resolver;
  44758. use React\Cache\ArrayCache;
  44759. use React\Cache\CacheInterface;
  44760. use React\Dns\Config\Config;
  44761. use React\Dns\Config\HostsFile;
  44762. use React\Dns\Query\CachingExecutor;
  44763. use React\Dns\Query\CoopExecutor;
  44764. use React\Dns\Query\ExecutorInterface;
  44765. use React\Dns\Query\FallbackExecutor;
  44766. use React\Dns\Query\HostsFileExecutor;
  44767. use React\Dns\Query\RetryExecutor;
  44768. use React\Dns\Query\SelectiveTransportExecutor;
  44769. use React\Dns\Query\TcpTransportExecutor;
  44770. use React\Dns\Query\TimeoutExecutor;
  44771. use React\Dns\Query\UdpTransportExecutor;
  44772. use React\EventLoop\Loop;
  44773. use React\EventLoop\LoopInterface;
  44774. final class Factory
  44775. {
  44776. public function create($config, $loop = null)
  44777. {
  44778. if ($loop !== null && !$loop instanceof LoopInterface) {
  44779. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  44780. }
  44781. $executor = $this->decorateHostsFileExecutor($this->createExecutor($config, $loop ?: Loop::get()));
  44782. return new Resolver($executor);
  44783. }
  44784. public function createCached($config, $loop = null, $cache = null)
  44785. {
  44786. if ($loop !== null && !$loop instanceof LoopInterface) {
  44787. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  44788. }
  44789. if ($cache !== null && !$cache instanceof CacheInterface) {
  44790. throw new \InvalidArgumentException('Argument #3 ($cache) expected null|React\Cache\CacheInterface');
  44791. }
  44792. if (!($cache instanceof CacheInterface)) {
  44793. $cache = new ArrayCache(256);
  44794. }
  44795. $executor = $this->createExecutor($config, $loop ?: Loop::get());
  44796. $executor = new CachingExecutor($executor, $cache);
  44797. $executor = $this->decorateHostsFileExecutor($executor);
  44798. return new Resolver($executor);
  44799. }
  44800. private function decorateHostsFileExecutor(ExecutorInterface $executor)
  44801. {
  44802. try {
  44803. $executor = new HostsFileExecutor(
  44804. HostsFile::loadFromPathBlocking(),
  44805. $executor
  44806. );
  44807. } catch (\RuntimeException $e) {
  44808. }
  44809. if (DIRECTORY_SEPARATOR === '\\') {
  44810. $executor = new HostsFileExecutor(
  44811. new HostsFile("127.0.0.1 localhost\n::1 localhost"),
  44812. $executor
  44813. );
  44814. }
  44815. return $executor;
  44816. }
  44817. private function createExecutor($nameserver, LoopInterface $loop)
  44818. {
  44819. if ($nameserver instanceof Config) {
  44820. if (!$nameserver->nameservers) {
  44821. throw new \UnderflowException('Empty config with no DNS servers');
  44822. }
  44823. $primary = reset($nameserver->nameservers);
  44824. $secondary = next($nameserver->nameservers);
  44825. $tertiary = next($nameserver->nameservers);
  44826. if ($tertiary !== false) {
  44827. return new CoopExecutor(
  44828. new RetryExecutor(
  44829. new FallbackExecutor(
  44830. $this->createSingleExecutor($primary, $loop),
  44831. new FallbackExecutor(
  44832. $this->createSingleExecutor($secondary, $loop),
  44833. $this->createSingleExecutor($tertiary, $loop)
  44834. )
  44835. )
  44836. )
  44837. );
  44838. } elseif ($secondary !== false) {
  44839. return new CoopExecutor(
  44840. new RetryExecutor(
  44841. new FallbackExecutor(
  44842. $this->createSingleExecutor($primary, $loop),
  44843. $this->createSingleExecutor($secondary, $loop)
  44844. )
  44845. )
  44846. );
  44847. } else {
  44848. $nameserver = $primary;
  44849. }
  44850. }
  44851. return new CoopExecutor(new RetryExecutor($this->createSingleExecutor($nameserver, $loop)));
  44852. }
  44853. private function createSingleExecutor($nameserver, LoopInterface $loop)
  44854. {
  44855. $parts = \parse_url($nameserver);
  44856. if (isset($parts['scheme']) && $parts['scheme'] === 'tcp') {
  44857. $executor = $this->createTcpExecutor($nameserver, $loop);
  44858. } elseif (isset($parts['scheme']) && $parts['scheme'] === 'udp') {
  44859. $executor = $this->createUdpExecutor($nameserver, $loop);
  44860. } else {
  44861. $executor = new SelectiveTransportExecutor(
  44862. $this->createUdpExecutor($nameserver, $loop),
  44863. $this->createTcpExecutor($nameserver, $loop)
  44864. );
  44865. }
  44866. return $executor;
  44867. }
  44868. private function createTcpExecutor($nameserver, LoopInterface $loop)
  44869. {
  44870. return new TimeoutExecutor(
  44871. new TcpTransportExecutor($nameserver, $loop),
  44872. 5.0,
  44873. $loop
  44874. );
  44875. }
  44876. private function createUdpExecutor($nameserver, LoopInterface $loop)
  44877. {
  44878. return new TimeoutExecutor(
  44879. new UdpTransportExecutor(
  44880. $nameserver,
  44881. $loop
  44882. ),
  44883. 5.0,
  44884. $loop
  44885. );
  44886. }
  44887. }
  44888. <?php
  44889. namespace React\Dns\Resolver;
  44890. use React\Dns\Model\Message;
  44891. use React\Dns\Query\ExecutorInterface;
  44892. use React\Dns\Query\Query;
  44893. use React\Dns\RecordNotFoundException;
  44894. final class Resolver implements ResolverInterface
  44895. {
  44896. private $executor;
  44897. public function __construct(ExecutorInterface $executor)
  44898. {
  44899. $this->executor = $executor;
  44900. }
  44901. public function resolve($domain)
  44902. {
  44903. return $this->resolveAll($domain, Message::TYPE_A)->then(function (array $ips) {
  44904. return $ips[array_rand($ips)];
  44905. });
  44906. }
  44907. public function resolveAll($domain, $type)
  44908. {
  44909. $query = new Query($domain, $type, Message::CLASS_IN);
  44910. $that = $this;
  44911. return $this->executor->query(
  44912. $query
  44913. )->then(function (Message $response) use ($query, $that) {
  44914. return $that->extractValues($query, $response);
  44915. });
  44916. }
  44917. public function extractValues(Query $query, Message $response)
  44918. {
  44919. $code = $response->rcode;
  44920. if ($code !== Message::RCODE_OK) {
  44921. switch ($code) {
  44922. case Message::RCODE_FORMAT_ERROR:
  44923. $message = 'Format Error';
  44924. break;
  44925. case Message::RCODE_SERVER_FAILURE:
  44926. $message = 'Server Failure';
  44927. break;
  44928. case Message::RCODE_NAME_ERROR:
  44929. $message = 'Non-Existent Domain / NXDOMAIN';
  44930. break;
  44931. case Message::RCODE_NOT_IMPLEMENTED:
  44932. $message = 'Not Implemented';
  44933. break;
  44934. case Message::RCODE_REFUSED:
  44935. $message = 'Refused';
  44936. break;
  44937. default:
  44938. $message = 'Unknown error response code ' . $code;
  44939. }
  44940. throw new RecordNotFoundException(
  44941. 'DNS query for ' . $query->describe() . ' returned an error response (' . $message . ')',
  44942. $code
  44943. );
  44944. }
  44945. $answers = $response->answers;
  44946. $addresses = $this->valuesByNameAndType($answers, $query->name, $query->type);
  44947. if (0 === count($addresses)) {
  44948. throw new RecordNotFoundException(
  44949. 'DNS query for ' . $query->describe() . ' did not return a valid answer (NOERROR / NODATA)'
  44950. );
  44951. }
  44952. return array_values($addresses);
  44953. }
  44954. private function valuesByNameAndType(array $answers, $name, $type)
  44955. {
  44956. $named = $this->filterByName($answers, $name);
  44957. $records = $this->filterByType($named, $type);
  44958. if ($records) {
  44959. return $this->mapRecordData($records);
  44960. }
  44961. $cnameRecords = $this->filterByType($named, Message::TYPE_CNAME);
  44962. if ($cnameRecords) {
  44963. $cnames = $this->mapRecordData($cnameRecords);
  44964. foreach ($cnames as $cname) {
  44965. $records = array_merge(
  44966. $records,
  44967. $this->valuesByNameAndType($answers, $cname, $type)
  44968. );
  44969. }
  44970. }
  44971. return $records;
  44972. }
  44973. private function filterByName(array $answers, $name)
  44974. {
  44975. return $this->filterByField($answers, 'name', $name);
  44976. }
  44977. private function filterByType(array $answers, $type)
  44978. {
  44979. return $this->filterByField($answers, 'type', $type);
  44980. }
  44981. private function filterByField(array $answers, $field, $value)
  44982. {
  44983. $value = strtolower($value);
  44984. return array_filter($answers, function ($answer) use ($field, $value) {
  44985. return $value === strtolower($answer->$field);
  44986. });
  44987. }
  44988. private function mapRecordData(array $records)
  44989. {
  44990. return array_map(function ($record) {
  44991. return $record->data;
  44992. }, $records);
  44993. }
  44994. }
  44995. <?php
  44996. namespace React\Dns\Resolver;
  44997. interface ResolverInterface
  44998. {
  44999. public function resolve($domain);
  45000. public function resolveAll($domain, $type);
  45001. }
  45002. <?php
  45003. namespace React\Socket;
  45004. use Evenement\EventEmitter;
  45005. use React\EventLoop\LoopInterface;
  45006. use React\Stream\DuplexResourceStream;
  45007. use React\Stream\Util;
  45008. use React\Stream\WritableResourceStream;
  45009. use React\Stream\WritableStreamInterface;
  45010. class Connection extends EventEmitter implements ConnectionInterface
  45011. {
  45012. public $unix = false;
  45013. public $encryptionEnabled = false;
  45014. public $stream;
  45015. private $input;
  45016. public function __construct($resource, LoopInterface $loop)
  45017. {
  45018. $clearCompleteBuffer = \PHP_VERSION_ID < 70215 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70303);
  45019. $limitWriteChunks = (\PHP_VERSION_ID < 70018 || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70104));
  45020. $this->input = new DuplexResourceStream(
  45021. $resource,
  45022. $loop,
  45023. $clearCompleteBuffer ? -1 : null,
  45024. new WritableResourceStream($resource, $loop, null, $limitWriteChunks ? 8192 : null)
  45025. );
  45026. $this->stream = $resource;
  45027. Util::forwardEvents($this->input, $this, array('data', 'end', 'error', 'close', 'pipe', 'drain'));
  45028. $this->input->on('close', array($this, 'close'));
  45029. }
  45030. public function isReadable()
  45031. {
  45032. return $this->input->isReadable();
  45033. }
  45034. public function isWritable()
  45035. {
  45036. return $this->input->isWritable();
  45037. }
  45038. public function pause()
  45039. {
  45040. $this->input->pause();
  45041. }
  45042. public function resume()
  45043. {
  45044. $this->input->resume();
  45045. }
  45046. public function pipe(WritableStreamInterface $dest, array $options = array())
  45047. {
  45048. return $this->input->pipe($dest, $options);
  45049. }
  45050. public function write($data)
  45051. {
  45052. return $this->input->write($data);
  45053. }
  45054. public function end($data = null)
  45055. {
  45056. $this->input->end($data);
  45057. }
  45058. public function close()
  45059. {
  45060. $this->input->close();
  45061. $this->handleClose();
  45062. $this->removeAllListeners();
  45063. }
  45064. public function handleClose()
  45065. {
  45066. if (!\is_resource($this->stream)) {
  45067. return;
  45068. }
  45069. @\stream_socket_shutdown($this->stream, \STREAM_SHUT_RDWR);
  45070. }
  45071. public function getRemoteAddress()
  45072. {
  45073. if (!\is_resource($this->stream)) {
  45074. return null;
  45075. }
  45076. return $this->parseAddress(\stream_socket_get_name($this->stream, true));
  45077. }
  45078. public function getLocalAddress()
  45079. {
  45080. if (!\is_resource($this->stream)) {
  45081. return null;
  45082. }
  45083. return $this->parseAddress(\stream_socket_get_name($this->stream, false));
  45084. }
  45085. private function parseAddress($address)
  45086. {
  45087. if ($address === false) {
  45088. return null;
  45089. }
  45090. if ($this->unix) {
  45091. if (\substr($address, -1) === ':' && \defined('HHVM_VERSION_ID') && \HHVM_VERSION_ID < 31900) {
  45092. $address = (string)\substr($address, 0, -1);
  45093. }
  45094. if ($address === '' || $address[0] === "\x00" ) {
  45095. return null;
  45096. }
  45097. return 'unix://' . $address;
  45098. }
  45099. $pos = \strrpos($address, ':');
  45100. if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
  45101. $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1);
  45102. }
  45103. return ($this->encryptionEnabled ? 'tls' : 'tcp') . '://' . $address;
  45104. }
  45105. }
  45106. <?php
  45107. namespace React\Socket;
  45108. use React\Dns\Resolver\ResolverInterface;
  45109. use React\Promise;
  45110. use React\Promise\PromiseInterface;
  45111. final class DnsConnector implements ConnectorInterface
  45112. {
  45113. private $connector;
  45114. private $resolver;
  45115. public function __construct(ConnectorInterface $connector, ResolverInterface $resolver)
  45116. {
  45117. $this->connector = $connector;
  45118. $this->resolver = $resolver;
  45119. }
  45120. public function connect($uri)
  45121. {
  45122. $original = $uri;
  45123. if (\strpos($uri, '://') === false) {
  45124. $uri = 'tcp://' . $uri;
  45125. $parts = \parse_url($uri);
  45126. if (isset($parts['scheme'])) {
  45127. unset($parts['scheme']);
  45128. }
  45129. } else {
  45130. $parts = \parse_url($uri);
  45131. }
  45132. if (!$parts || !isset($parts['host'])) {
  45133. return Promise\reject(new \InvalidArgumentException(
  45134. 'Given URI "' . $original . '" is invalid (EINVAL)',
  45135. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45136. ));
  45137. }
  45138. $host = \trim($parts['host'], '[]');
  45139. $connector = $this->connector;
  45140. if (@\inet_pton($host) !== false) {
  45141. return $connector->connect($original);
  45142. }
  45143. $promise = $this->resolver->resolve($host);
  45144. $resolved = null;
  45145. return new Promise\Promise(
  45146. function ($resolve, $reject) use (&$promise, &$resolved, $uri, $connector, $host, $parts) {
  45147. $promise->then(function ($ip) use (&$promise, &$resolved, $uri, $connector, $host, $parts) {
  45148. $resolved = $ip;
  45149. return $promise = $connector->connect(
  45150. Connector::uri($parts, $host, $ip)
  45151. )->then(null, function (\Exception $e) use ($uri) {
  45152. if ($e instanceof \RuntimeException) {
  45153. $message = \preg_replace('/^(Connection to [^ ]+)[&?]hostname=[^ &]+/', '$1', $e->getMessage());
  45154. $e = new \RuntimeException(
  45155. 'Connection to ' . $uri . ' failed: ' . $message,
  45156. $e->getCode(),
  45157. $e
  45158. );
  45159. $r = new \ReflectionProperty('Exception', 'trace');
  45160. $r->setAccessible(true);
  45161. $trace = $r->getValue($e);
  45162. foreach ($trace as $ti => $one) {
  45163. if (isset($one['args'])) {
  45164. foreach ($one['args'] as $ai => $arg) {
  45165. if ($arg instanceof \Closure) {
  45166. $trace[$ti]['args'][$ai] = 'Object(' . \get_class($arg) . ')';
  45167. }
  45168. }
  45169. }
  45170. }
  45171. $r->setValue($e, $trace);
  45172. }
  45173. throw $e;
  45174. });
  45175. }, function ($e) use ($uri, $reject) {
  45176. $reject(new \RuntimeException('Connection to ' . $uri .' failed during DNS lookup: ' . $e->getMessage(), 0, $e));
  45177. })->then($resolve, $reject);
  45178. },
  45179. function ($_, $reject) use (&$promise, &$resolved, $uri) {
  45180. if ($resolved === null) {
  45181. $reject(new \RuntimeException(
  45182. 'Connection to ' . $uri . ' cancelled during DNS lookup (ECONNABORTED)',
  45183. \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
  45184. ));
  45185. }
  45186. if ($promise instanceof PromiseInterface && \method_exists($promise, 'cancel')) {
  45187. $_ = $reject = null;
  45188. $promise->cancel();
  45189. $promise = null;
  45190. }
  45191. }
  45192. );
  45193. }
  45194. }
  45195. <?php
  45196. namespace React\Socket;
  45197. class FixedUriConnector implements ConnectorInterface
  45198. {
  45199. private $uri;
  45200. private $connector;
  45201. public function __construct($uri, ConnectorInterface $connector)
  45202. {
  45203. $this->uri = $uri;
  45204. $this->connector = $connector;
  45205. }
  45206. public function connect($_)
  45207. {
  45208. return $this->connector->connect($this->uri);
  45209. }
  45210. }
  45211. <?php
  45212. namespace React\Socket;
  45213. use React\EventLoop\LoopInterface;
  45214. use React\Promise\Deferred;
  45215. use RuntimeException;
  45216. use UnexpectedValueException;
  45217. class StreamEncryption
  45218. {
  45219. private $loop;
  45220. private $method;
  45221. private $server;
  45222. public function __construct(LoopInterface $loop, $server = true)
  45223. {
  45224. $this->loop = $loop;
  45225. $this->server = $server;
  45226. if ($server) {
  45227. $this->method = \STREAM_CRYPTO_METHOD_TLS_SERVER;
  45228. if (\PHP_VERSION_ID < 70200 && \PHP_VERSION_ID >= 50600) {
  45229. $this->method |= \STREAM_CRYPTO_METHOD_TLSv1_0_SERVER | \STREAM_CRYPTO_METHOD_TLSv1_1_SERVER | \STREAM_CRYPTO_METHOD_TLSv1_2_SERVER;
  45230. }
  45231. } else {
  45232. $this->method = \STREAM_CRYPTO_METHOD_TLS_CLIENT;
  45233. if (\PHP_VERSION_ID < 70200 && \PHP_VERSION_ID >= 50600) {
  45234. $this->method |= \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
  45235. }
  45236. }
  45237. }
  45238. public function enable(Connection $stream)
  45239. {
  45240. return $this->toggle($stream, true);
  45241. }
  45242. public function toggle(Connection $stream, $toggle)
  45243. {
  45244. $stream->pause();
  45245. $deferred = new Deferred(function () {
  45246. throw new \RuntimeException();
  45247. });
  45248. $socket = $stream->stream;
  45249. $method = $this->method;
  45250. $context = \stream_context_get_options($socket);
  45251. if (isset($context['ssl']['crypto_method'])) {
  45252. $method = $context['ssl']['crypto_method'];
  45253. }
  45254. $that = $this;
  45255. $toggleCrypto = function () use ($socket, $deferred, $toggle, $method, $that) {
  45256. $that->toggleCrypto($socket, $deferred, $toggle, $method);
  45257. };
  45258. $this->loop->addReadStream($socket, $toggleCrypto);
  45259. if (!$this->server) {
  45260. $toggleCrypto();
  45261. }
  45262. $loop = $this->loop;
  45263. return $deferred->promise()->then(function () use ($stream, $socket, $loop, $toggle) {
  45264. $loop->removeReadStream($socket);
  45265. $stream->encryptionEnabled = $toggle;
  45266. $stream->resume();
  45267. return $stream;
  45268. }, function($error) use ($stream, $socket, $loop) {
  45269. $loop->removeReadStream($socket);
  45270. $stream->resume();
  45271. throw $error;
  45272. });
  45273. }
  45274. public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
  45275. {
  45276. $error = null;
  45277. \set_error_handler(function ($_, $errstr) use (&$error) {
  45278. $error = \str_replace(array("\r", "\n"), ' ', $errstr);
  45279. if (($pos = \strpos($error, "): ")) !== false) {
  45280. $error = \substr($error, $pos + 3);
  45281. }
  45282. });
  45283. $result = \stream_socket_enable_crypto($socket, $toggle, $method);
  45284. \restore_error_handler();
  45285. if (true === $result) {
  45286. $deferred->resolve(null);
  45287. } else if (false === $result) {
  45288. $d = $deferred;
  45289. $deferred = null;
  45290. if (\feof($socket) || $error === null) {
  45291. $d->reject(new \UnexpectedValueException(
  45292. 'Connection lost during TLS handshake (ECONNRESET)',
  45293. \defined('SOCKET_ECONNRESET') ? \SOCKET_ECONNRESET : 104
  45294. ));
  45295. } else {
  45296. $d->reject(new \UnexpectedValueException(
  45297. $error
  45298. ));
  45299. }
  45300. } else {
  45301. }
  45302. }
  45303. }
  45304. <?php
  45305. namespace React\Socket;
  45306. use React\Stream\DuplexStreamInterface;
  45307. interface ConnectionInterface extends DuplexStreamInterface
  45308. {
  45309. public function getRemoteAddress();
  45310. public function getLocalAddress();
  45311. }
  45312. <?php
  45313. namespace React\Socket;
  45314. use React\EventLoop\Loop;
  45315. use React\EventLoop\LoopInterface;
  45316. use React\Promise;
  45317. use BadMethodCallException;
  45318. use InvalidArgumentException;
  45319. use UnexpectedValueException;
  45320. final class SecureConnector implements ConnectorInterface
  45321. {
  45322. private $connector;
  45323. private $streamEncryption;
  45324. private $context;
  45325. public function __construct(ConnectorInterface $connector, $loop = null, array $context = array())
  45326. {
  45327. if ($loop !== null && !$loop instanceof LoopInterface) {
  45328. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  45329. }
  45330. $this->connector = $connector;
  45331. $this->streamEncryption = new StreamEncryption($loop ?: Loop::get(), false);
  45332. $this->context = $context;
  45333. }
  45334. public function connect($uri)
  45335. {
  45336. if (!\function_exists('stream_socket_enable_crypto')) {
  45337. return Promise\reject(new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)'));
  45338. }
  45339. if (\strpos($uri, '://') === false) {
  45340. $uri = 'tls://' . $uri;
  45341. }
  45342. $parts = \parse_url($uri);
  45343. if (!$parts || !isset($parts['scheme']) || $parts['scheme'] !== 'tls') {
  45344. return Promise\reject(new \InvalidArgumentException(
  45345. 'Given URI "' . $uri . '" is invalid (EINVAL)',
  45346. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45347. ));
  45348. }
  45349. $context = $this->context;
  45350. $encryption = $this->streamEncryption;
  45351. $connected = false;
  45352. $promise = $this->connector->connect(
  45353. \str_replace('tls://', '', $uri)
  45354. )->then(function (ConnectionInterface $connection) use ($context, $encryption, $uri, &$promise, &$connected) {
  45355. $connected = true;
  45356. if (!$connection instanceof Connection) {
  45357. $connection->close();
  45358. throw new \UnexpectedValueException('Base connector does not use internal Connection class exposing stream resource');
  45359. }
  45360. foreach ($context as $name => $value) {
  45361. \stream_context_set_option($connection->stream, 'ssl', $name, $value);
  45362. }
  45363. return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
  45364. $connection->close();
  45365. throw new \RuntimeException(
  45366. 'Connection to ' . $uri . ' failed during TLS handshake: ' . $error->getMessage(),
  45367. $error->getCode()
  45368. );
  45369. });
  45370. }, function (\Exception $e) use ($uri) {
  45371. if ($e instanceof \RuntimeException) {
  45372. $message = \preg_replace('/^Connection to [^ ]+/', '', $e->getMessage());
  45373. $e = new \RuntimeException(
  45374. 'Connection to ' . $uri . $message,
  45375. $e->getCode(),
  45376. $e
  45377. );
  45378. $r = new \ReflectionProperty('Exception', 'trace');
  45379. $r->setAccessible(true);
  45380. $trace = $r->getValue($e);
  45381. foreach ($trace as $ti => $one) {
  45382. if (isset($one['args'])) {
  45383. foreach ($one['args'] as $ai => $arg) {
  45384. if ($arg instanceof \Closure) {
  45385. $trace[$ti]['args'][$ai] = 'Object(' . \get_class($arg) . ')';
  45386. }
  45387. }
  45388. }
  45389. }
  45390. $r->setValue($e, $trace);
  45391. }
  45392. throw $e;
  45393. });
  45394. return new \React\Promise\Promise(
  45395. function ($resolve, $reject) use ($promise) {
  45396. $promise->then($resolve, $reject);
  45397. },
  45398. function ($_, $reject) use (&$promise, $uri, &$connected) {
  45399. if ($connected) {
  45400. $reject(new \RuntimeException(
  45401. 'Connection to ' . $uri . ' cancelled during TLS handshake (ECONNABORTED)',
  45402. \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
  45403. ));
  45404. }
  45405. $promise->cancel();
  45406. $promise = null;
  45407. }
  45408. );
  45409. }
  45410. }
  45411. <?php
  45412. namespace React\Socket;
  45413. use Evenement\EventEmitter;
  45414. use React\EventLoop\Loop;
  45415. use React\EventLoop\LoopInterface;
  45416. use Exception;
  45417. final class Server extends EventEmitter implements ServerInterface
  45418. {
  45419. private $server;
  45420. public function __construct($uri, $loop = null, array $context = array())
  45421. {
  45422. if ($loop !== null && !$loop instanceof LoopInterface) {
  45423. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  45424. }
  45425. $loop = $loop ?: Loop::get();
  45426. if ($context && (!isset($context['tcp']) && !isset($context['tls']) && !isset($context['unix']))) {
  45427. $context = array('tcp' => $context);
  45428. }
  45429. $context += array(
  45430. 'tcp' => array(),
  45431. 'tls' => array(),
  45432. 'unix' => array()
  45433. );
  45434. $scheme = 'tcp';
  45435. $pos = \strpos($uri, '://');
  45436. if ($pos !== false) {
  45437. $scheme = \substr($uri, 0, $pos);
  45438. }
  45439. if ($scheme === 'unix') {
  45440. $server = new UnixServer($uri, $loop, $context['unix']);
  45441. } else {
  45442. $server = new TcpServer(str_replace('tls://', '', $uri), $loop, $context['tcp']);
  45443. if ($scheme === 'tls') {
  45444. $server = new SecureServer($server, $loop, $context['tls']);
  45445. }
  45446. }
  45447. $this->server = $server;
  45448. $that = $this;
  45449. $server->on('connection', function (ConnectionInterface $conn) use ($that) {
  45450. $that->emit('connection', array($conn));
  45451. });
  45452. $server->on('error', function (Exception $error) use ($that) {
  45453. $that->emit('error', array($error));
  45454. });
  45455. }
  45456. public function getAddress()
  45457. {
  45458. return $this->server->getAddress();
  45459. }
  45460. public function pause()
  45461. {
  45462. $this->server->pause();
  45463. }
  45464. public function resume()
  45465. {
  45466. $this->server->resume();
  45467. }
  45468. public function close()
  45469. {
  45470. $this->server->close();
  45471. }
  45472. }
  45473. <?php
  45474. namespace React\Socket;
  45475. use Evenement\EventEmitter;
  45476. use React\EventLoop\Loop;
  45477. use React\EventLoop\LoopInterface;
  45478. final class FdServer extends EventEmitter implements ServerInterface
  45479. {
  45480. private $master;
  45481. private $loop;
  45482. private $unix = false;
  45483. private $listening = false;
  45484. public function __construct($fd, $loop = null)
  45485. {
  45486. if (\preg_match('#^php://fd/(\d+)$#', $fd, $m)) {
  45487. $fd = (int) $m[1];
  45488. }
  45489. if (!\is_int($fd) || $fd < 0 || $fd >= \PHP_INT_MAX) {
  45490. throw new \InvalidArgumentException(
  45491. 'Invalid FD number given (EINVAL)',
  45492. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45493. );
  45494. }
  45495. if ($loop !== null && !$loop instanceof LoopInterface) {
  45496. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  45497. }
  45498. $this->loop = $loop ?: Loop::get();
  45499. $errno = 0;
  45500. $errstr = '';
  45501. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  45502. \preg_match('/\[(\d+)\]: (.*)/', $error, $m);
  45503. $errno = isset($m[1]) ? (int) $m[1] : 0;
  45504. $errstr = isset($m[2]) ? $m[2] : $error;
  45505. });
  45506. $this->master = \fopen('php://fd/' . $fd, 'r+');
  45507. \restore_error_handler();
  45508. if (false === $this->master) {
  45509. throw new \RuntimeException(
  45510. 'Failed to listen on FD ' . $fd . ': ' . $errstr . SocketServer::errconst($errno),
  45511. $errno
  45512. );
  45513. }
  45514. $meta = \stream_get_meta_data($this->master);
  45515. if (!isset($meta['stream_type']) || $meta['stream_type'] !== 'tcp_socket') {
  45516. \fclose($this->master);
  45517. $errno = \defined('SOCKET_ENOTSOCK') ? \SOCKET_ENOTSOCK : 88;
  45518. $errstr = \function_exists('socket_strerror') ? \socket_strerror($errno) : 'Not a socket';
  45519. throw new \RuntimeException(
  45520. 'Failed to listen on FD ' . $fd . ': ' . $errstr . ' (ENOTSOCK)',
  45521. $errno
  45522. );
  45523. }
  45524. if (\stream_socket_get_name($this->master, true) !== false) {
  45525. \fclose($this->master);
  45526. $errno = \defined('SOCKET_EISCONN') ? \SOCKET_EISCONN : 106;
  45527. $errstr = \function_exists('socket_strerror') ? \socket_strerror($errno) : 'Socket is connected';
  45528. throw new \RuntimeException(
  45529. 'Failed to listen on FD ' . $fd . ': ' . $errstr . ' (EISCONN)',
  45530. $errno
  45531. );
  45532. }
  45533. $this->unix = \parse_url($this->getAddress(), \PHP_URL_PORT) === false;
  45534. \stream_set_blocking($this->master, false);
  45535. $this->resume();
  45536. }
  45537. public function getAddress()
  45538. {
  45539. if (!\is_resource($this->master)) {
  45540. return null;
  45541. }
  45542. $address = \stream_socket_get_name($this->master, false);
  45543. if ($this->unix === true) {
  45544. return 'unix://' . $address;
  45545. }
  45546. $pos = \strrpos($address, ':');
  45547. if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
  45548. $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1);
  45549. }
  45550. return 'tcp://' . $address;
  45551. }
  45552. public function pause()
  45553. {
  45554. if (!$this->listening) {
  45555. return;
  45556. }
  45557. $this->loop->removeReadStream($this->master);
  45558. $this->listening = false;
  45559. }
  45560. public function resume()
  45561. {
  45562. if ($this->listening || !\is_resource($this->master)) {
  45563. return;
  45564. }
  45565. $that = $this;
  45566. $this->loop->addReadStream($this->master, function ($master) use ($that) {
  45567. try {
  45568. $newSocket = SocketServer::accept($master);
  45569. } catch (\RuntimeException $e) {
  45570. $that->emit('error', array($e));
  45571. return;
  45572. }
  45573. $that->handleConnection($newSocket);
  45574. });
  45575. $this->listening = true;
  45576. }
  45577. public function close()
  45578. {
  45579. if (!\is_resource($this->master)) {
  45580. return;
  45581. }
  45582. $this->pause();
  45583. \fclose($this->master);
  45584. $this->removeAllListeners();
  45585. }
  45586. public function handleConnection($socket)
  45587. {
  45588. $connection = new Connection($socket, $this->loop);
  45589. $connection->unix = $this->unix;
  45590. $this->emit('connection', array($connection));
  45591. }
  45592. }
  45593. <?php
  45594. namespace React\Socket;
  45595. use React\EventLoop\Loop;
  45596. use React\EventLoop\LoopInterface;
  45597. use React\Promise;
  45598. use InvalidArgumentException;
  45599. use RuntimeException;
  45600. final class TcpConnector implements ConnectorInterface
  45601. {
  45602. private $loop;
  45603. private $context;
  45604. public function __construct($loop = null, array $context = array())
  45605. {
  45606. if ($loop !== null && !$loop instanceof LoopInterface) {
  45607. throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
  45608. }
  45609. $this->loop = $loop ?: Loop::get();
  45610. $this->context = $context;
  45611. }
  45612. public function connect($uri)
  45613. {
  45614. if (\strpos($uri, '://') === false) {
  45615. $uri = 'tcp://' . $uri;
  45616. }
  45617. $parts = \parse_url($uri);
  45618. if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
  45619. return Promise\reject(new \InvalidArgumentException(
  45620. 'Given URI "' . $uri . '" is invalid (EINVAL)',
  45621. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45622. ));
  45623. }
  45624. $ip = \trim($parts['host'], '[]');
  45625. if (@\inet_pton($ip) === false) {
  45626. return Promise\reject(new \InvalidArgumentException(
  45627. 'Given URI "' . $uri . '" does not contain a valid host IP (EINVAL)',
  45628. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45629. ));
  45630. }
  45631. $context = array(
  45632. 'socket' => $this->context
  45633. );
  45634. $args = array();
  45635. if (isset($parts['query'])) {
  45636. \parse_str($parts['query'], $args);
  45637. }
  45638. if (isset($args['hostname'])) {
  45639. $context['ssl'] = array(
  45640. 'SNI_enabled' => true,
  45641. 'peer_name' => $args['hostname']
  45642. );
  45643. if (\PHP_VERSION_ID < 50600) {
  45644. $context['ssl'] += array(
  45645. 'SNI_server_name' => $args['hostname'],
  45646. 'CN_match' => $args['hostname']
  45647. );
  45648. }
  45649. }
  45650. $remote = 'tcp://' . $parts['host'] . ':' . $parts['port'];
  45651. $stream = @\stream_socket_client(
  45652. $remote,
  45653. $errno,
  45654. $errstr,
  45655. 0,
  45656. \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT,
  45657. \stream_context_create($context)
  45658. );
  45659. if (false === $stream) {
  45660. return Promise\reject(new \RuntimeException(
  45661. 'Connection to ' . $uri . ' failed: ' . $errstr . SocketServer::errconst($errno),
  45662. $errno
  45663. ));
  45664. }
  45665. $loop = $this->loop;
  45666. return new Promise\Promise(function ($resolve, $reject) use ($loop, $stream, $uri) {
  45667. $loop->addWriteStream($stream, function ($stream) use ($loop, $resolve, $reject, $uri) {
  45668. $loop->removeWriteStream($stream);
  45669. if (false === \stream_socket_get_name($stream, true)) {
  45670. if (\function_exists('socket_import_stream')) {
  45671. $socket = \socket_import_stream($stream);
  45672. $errno = \socket_get_option($socket, \SOL_SOCKET, \SO_ERROR);
  45673. $errstr = \socket_strerror($errno);
  45674. } elseif (\PHP_OS === 'Linux') {
  45675. $errno = 0;
  45676. $errstr = '';
  45677. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  45678. \preg_match('/errno=(\d+) (.+)/', $error, $m);
  45679. $errno = isset($m[1]) ? (int) $m[1] : 0;
  45680. $errstr = isset($m[2]) ? $m[2] : $error;
  45681. });
  45682. \fwrite($stream, \PHP_EOL);
  45683. \restore_error_handler();
  45684. } else {
  45685. $errno = \defined('SOCKET_ECONNREFUSED') ? \SOCKET_ECONNREFUSED : 111;
  45686. $errstr = 'Connection refused?';
  45687. }
  45688. \fclose($stream);
  45689. $reject(new \RuntimeException(
  45690. 'Connection to ' . $uri . ' failed: ' . $errstr . SocketServer::errconst($errno),
  45691. $errno
  45692. ));
  45693. } else {
  45694. $resolve(new Connection($stream, $loop));
  45695. }
  45696. });
  45697. }, function () use ($loop, $stream, $uri) {
  45698. $loop->removeWriteStream($stream);
  45699. \fclose($stream);
  45700. if (\PHP_VERSION_ID < 50400 && \is_resource($stream)) {
  45701. \fclose($stream);
  45702. }
  45703. throw new \RuntimeException(
  45704. 'Connection to ' . $uri . ' cancelled during TCP/IP handshake (ECONNABORTED)',
  45705. \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
  45706. );
  45707. });
  45708. }
  45709. }
  45710. <?php
  45711. namespace React\Socket;
  45712. use Evenement\EventEmitter;
  45713. use React\EventLoop\Loop;
  45714. use React\EventLoop\LoopInterface;
  45715. use BadMethodCallException;
  45716. use UnexpectedValueException;
  45717. final class SecureServer extends EventEmitter implements ServerInterface
  45718. {
  45719. private $tcp;
  45720. private $encryption;
  45721. private $context;
  45722. public function __construct(ServerInterface $tcp, $loop = null, array $context = array())
  45723. {
  45724. if ($loop !== null && !$loop instanceof LoopInterface) {
  45725. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  45726. }
  45727. if (!\function_exists('stream_socket_enable_crypto')) {
  45728. throw new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)');
  45729. }
  45730. $context += array(
  45731. 'passphrase' => ''
  45732. );
  45733. $this->tcp = $tcp;
  45734. $this->encryption = new StreamEncryption($loop ?: Loop::get());
  45735. $this->context = $context;
  45736. $that = $this;
  45737. $this->tcp->on('connection', function ($connection) use ($that) {
  45738. $that->handleConnection($connection);
  45739. });
  45740. $this->tcp->on('error', function ($error) use ($that) {
  45741. $that->emit('error', array($error));
  45742. });
  45743. }
  45744. public function getAddress()
  45745. {
  45746. $address = $this->tcp->getAddress();
  45747. if ($address === null) {
  45748. return null;
  45749. }
  45750. return \str_replace('tcp://' , 'tls://', $address);
  45751. }
  45752. public function pause()
  45753. {
  45754. $this->tcp->pause();
  45755. }
  45756. public function resume()
  45757. {
  45758. $this->tcp->resume();
  45759. }
  45760. public function close()
  45761. {
  45762. return $this->tcp->close();
  45763. }
  45764. public function handleConnection(ConnectionInterface $connection)
  45765. {
  45766. if (!$connection instanceof Connection) {
  45767. $this->emit('error', array(new \UnexpectedValueException('Base server does not use internal Connection class exposing stream resource')));
  45768. $connection->close();
  45769. return;
  45770. }
  45771. foreach ($this->context as $name => $value) {
  45772. \stream_context_set_option($connection->stream, 'ssl', $name, $value);
  45773. }
  45774. $remote = $connection->getRemoteAddress();
  45775. $that = $this;
  45776. $this->encryption->enable($connection)->then(
  45777. function ($conn) use ($that) {
  45778. $that->emit('connection', array($conn));
  45779. },
  45780. function ($error) use ($that, $connection, $remote) {
  45781. $error = new \RuntimeException(
  45782. 'Connection from ' . $remote . ' failed during TLS handshake: ' . $error->getMessage(),
  45783. $error->getCode()
  45784. );
  45785. $that->emit('error', array($error));
  45786. $connection->close();
  45787. }
  45788. );
  45789. }
  45790. }
  45791. <?php
  45792. namespace React\Socket;
  45793. use React\EventLoop\Loop;
  45794. use React\EventLoop\LoopInterface;
  45795. use React\Promise;
  45796. use InvalidArgumentException;
  45797. use RuntimeException;
  45798. final class UnixConnector implements ConnectorInterface
  45799. {
  45800. private $loop;
  45801. public function __construct($loop = null)
  45802. {
  45803. if ($loop !== null && !$loop instanceof LoopInterface) {
  45804. throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
  45805. }
  45806. $this->loop = $loop ?: Loop::get();
  45807. }
  45808. public function connect($path)
  45809. {
  45810. if (\strpos($path, '://') === false) {
  45811. $path = 'unix://' . $path;
  45812. } elseif (\substr($path, 0, 7) !== 'unix://') {
  45813. return Promise\reject(new \InvalidArgumentException(
  45814. 'Given URI "' . $path . '" is invalid (EINVAL)',
  45815. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45816. ));
  45817. }
  45818. $resource = @\stream_socket_client($path, $errno, $errstr, 1.0);
  45819. if (!$resource) {
  45820. return Promise\reject(new \RuntimeException(
  45821. 'Unable to connect to unix domain socket "' . $path . '": ' . $errstr . SocketServer::errconst($errno),
  45822. $errno
  45823. ));
  45824. }
  45825. $connection = new Connection($resource, $this->loop);
  45826. $connection->unix = true;
  45827. return Promise\resolve($connection);
  45828. }
  45829. }
  45830. <?php
  45831. namespace React\Socket;
  45832. use Evenement\EventEmitter;
  45833. use React\EventLoop\Loop;
  45834. use React\EventLoop\LoopInterface;
  45835. use InvalidArgumentException;
  45836. use RuntimeException;
  45837. final class UnixServer extends EventEmitter implements ServerInterface
  45838. {
  45839. private $master;
  45840. private $loop;
  45841. private $listening = false;
  45842. public function __construct($path, $loop = null, array $context = array())
  45843. {
  45844. if ($loop !== null && !$loop instanceof LoopInterface) {
  45845. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  45846. }
  45847. $this->loop = $loop ?: Loop::get();
  45848. if (\strpos($path, '://') === false) {
  45849. $path = 'unix://' . $path;
  45850. } elseif (\substr($path, 0, 7) !== 'unix://') {
  45851. throw new \InvalidArgumentException(
  45852. 'Given URI "' . $path . '" is invalid (EINVAL)',
  45853. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  45854. );
  45855. }
  45856. $errno = 0;
  45857. $errstr = '';
  45858. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  45859. if (\preg_match('/\(([^\)]+)\)|\[(\d+)\]: (.*)/', $error, $match)) {
  45860. $errstr = isset($match[3]) ? $match['3'] : $match[1];
  45861. $errno = isset($match[2]) ? (int)$match[2] : 0;
  45862. }
  45863. });
  45864. $this->master = \stream_socket_server(
  45865. $path,
  45866. $errno,
  45867. $errstr,
  45868. \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN,
  45869. \stream_context_create(array('socket' => $context))
  45870. );
  45871. \restore_error_handler();
  45872. if (false === $this->master) {
  45873. throw new \RuntimeException(
  45874. 'Failed to listen on Unix domain socket "' . $path . '": ' . $errstr . SocketServer::errconst($errno),
  45875. $errno
  45876. );
  45877. }
  45878. \stream_set_blocking($this->master, 0);
  45879. $this->resume();
  45880. }
  45881. public function getAddress()
  45882. {
  45883. if (!\is_resource($this->master)) {
  45884. return null;
  45885. }
  45886. return 'unix://' . \stream_socket_get_name($this->master, false);
  45887. }
  45888. public function pause()
  45889. {
  45890. if (!$this->listening) {
  45891. return;
  45892. }
  45893. $this->loop->removeReadStream($this->master);
  45894. $this->listening = false;
  45895. }
  45896. public function resume()
  45897. {
  45898. if ($this->listening || !is_resource($this->master)) {
  45899. return;
  45900. }
  45901. $that = $this;
  45902. $this->loop->addReadStream($this->master, function ($master) use ($that) {
  45903. try {
  45904. $newSocket = SocketServer::accept($master);
  45905. } catch (\RuntimeException $e) {
  45906. $that->emit('error', array($e));
  45907. return;
  45908. }
  45909. $that->handleConnection($newSocket);
  45910. });
  45911. $this->listening = true;
  45912. }
  45913. public function close()
  45914. {
  45915. if (!\is_resource($this->master)) {
  45916. return;
  45917. }
  45918. $this->pause();
  45919. \fclose($this->master);
  45920. $this->removeAllListeners();
  45921. }
  45922. public function handleConnection($socket)
  45923. {
  45924. $connection = new Connection($socket, $this->loop);
  45925. $connection->unix = true;
  45926. $this->emit('connection', array(
  45927. $connection
  45928. ));
  45929. }
  45930. }
  45931. <?php
  45932. namespace React\Socket;
  45933. use React\Dns\Model\Message;
  45934. use React\Dns\Resolver\ResolverInterface;
  45935. use React\EventLoop\LoopInterface;
  45936. use React\EventLoop\TimerInterface;
  45937. use React\Promise;
  45938. use React\Promise\PromiseInterface;
  45939. final class HappyEyeBallsConnectionBuilder
  45940. {
  45941. const CONNECTION_ATTEMPT_DELAY = 0.1;
  45942. const RESOLUTION_DELAY = 0.05;
  45943. public $loop;
  45944. public $connector;
  45945. public $resolver;
  45946. public $uri;
  45947. public $host;
  45948. public $resolved = array(
  45949. Message::TYPE_A => false,
  45950. Message::TYPE_AAAA => false,
  45951. );
  45952. public $resolverPromises = array();
  45953. public $connectionPromises = array();
  45954. public $connectQueue = array();
  45955. public $nextAttemptTimer;
  45956. public $parts;
  45957. public $ipsCount = 0;
  45958. public $failureCount = 0;
  45959. public $resolve;
  45960. public $reject;
  45961. public $lastErrorFamily;
  45962. public $lastError6;
  45963. public $lastError4;
  45964. public function __construct(LoopInterface $loop, ConnectorInterface $connector, ResolverInterface $resolver, $uri, $host, $parts)
  45965. {
  45966. $this->loop = $loop;
  45967. $this->connector = $connector;
  45968. $this->resolver = $resolver;
  45969. $this->uri = $uri;
  45970. $this->host = $host;
  45971. $this->parts = $parts;
  45972. }
  45973. public function connect()
  45974. {
  45975. $that = $this;
  45976. return new Promise\Promise(function ($resolve, $reject) use ($that) {
  45977. $lookupResolve = function ($type) use ($that, $resolve, $reject) {
  45978. return function (array $ips) use ($that, $type, $resolve, $reject) {
  45979. unset($that->resolverPromises[$type]);
  45980. $that->resolved[$type] = true;
  45981. $that->mixIpsIntoConnectQueue($ips);
  45982. if ($that->nextAttemptTimer === null && $that->connectQueue) {
  45983. $that->check($resolve, $reject);
  45984. }
  45985. };
  45986. };
  45987. $that->resolverPromises[Message::TYPE_AAAA] = $that->resolve(Message::TYPE_AAAA, $reject)->then($lookupResolve(Message::TYPE_AAAA));
  45988. $that->resolverPromises[Message::TYPE_A] = $that->resolve(Message::TYPE_A, $reject)->then(function (array $ips) use ($that) {
  45989. if ($that->resolved[Message::TYPE_AAAA] === true || !$ips) {
  45990. return $ips;
  45991. }
  45992. $deferred = new Promise\Deferred(function () use (&$ips) {
  45993. $ips = array();
  45994. });
  45995. $timer = $that->loop->addTimer($that::RESOLUTION_DELAY, function () use ($deferred, $ips) {
  45996. $deferred->resolve($ips);
  45997. });
  45998. $that->resolverPromises[Message::TYPE_AAAA]->then(function () use ($that, $timer, $deferred, &$ips) {
  45999. $that->loop->cancelTimer($timer);
  46000. $deferred->resolve($ips);
  46001. });
  46002. return $deferred->promise();
  46003. })->then($lookupResolve(Message::TYPE_A));
  46004. }, function ($_, $reject) use ($that) {
  46005. $reject(new \RuntimeException(
  46006. 'Connection to ' . $that->uri . ' cancelled' . (!$that->connectionPromises ? ' during DNS lookup' : '') . ' (ECONNABORTED)',
  46007. \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
  46008. ));
  46009. $_ = $reject = null;
  46010. $that->cleanUp();
  46011. });
  46012. }
  46013. public function resolve($type, $reject)
  46014. {
  46015. $that = $this;
  46016. return $that->resolver->resolveAll($that->host, $type)->then(null, function (\Exception $e) use ($type, $reject, $that) {
  46017. unset($that->resolverPromises[$type]);
  46018. $that->resolved[$type] = true;
  46019. if ($type === Message::TYPE_A) {
  46020. $that->lastError4 = $e->getMessage();
  46021. $that->lastErrorFamily = 4;
  46022. } else {
  46023. $that->lastError6 = $e->getMessage();
  46024. $that->lastErrorFamily = 6;
  46025. }
  46026. if ($that->nextAttemptTimer !== null && !$that->connectQueue) {
  46027. $that->loop->cancelTimer($that->nextAttemptTimer);
  46028. $that->nextAttemptTimer = null;
  46029. }
  46030. if ($that->hasBeenResolved() && $that->ipsCount === 0) {
  46031. $reject(new \RuntimeException(
  46032. $that->error(),
  46033. 0,
  46034. $e
  46035. ));
  46036. }
  46037. return array();
  46038. });
  46039. }
  46040. public function check($resolve, $reject)
  46041. {
  46042. $ip = \array_shift($this->connectQueue);
  46043. $this->connectionPromises[] = $this->attemptConnection($ip);
  46044. \end($this->connectionPromises);
  46045. $index = \key($this->connectionPromises);
  46046. $that = $this;
  46047. $that->connectionPromises[$index]->then(function ($connection) use ($that, $index, $resolve) {
  46048. unset($that->connectionPromises[$index]);
  46049. $that->cleanUp();
  46050. $resolve($connection);
  46051. }, function (\Exception $e) use ($that, $index, $ip, $resolve, $reject) {
  46052. unset($that->connectionPromises[$index]);
  46053. $that->failureCount++;
  46054. $message = \preg_replace('/^(Connection to [^ ]+)[&?]hostname=[^ &]+/', '$1', $e->getMessage());
  46055. if (\strpos($ip, ':') === false) {
  46056. $that->lastError4 = $message;
  46057. $that->lastErrorFamily = 4;
  46058. } else {
  46059. $that->lastError6 = $message;
  46060. $that->lastErrorFamily = 6;
  46061. }
  46062. if ($that->connectQueue) {
  46063. if ($that->nextAttemptTimer !== null) {
  46064. $that->loop->cancelTimer($that->nextAttemptTimer);
  46065. $that->nextAttemptTimer = null;
  46066. }
  46067. $that->check($resolve, $reject);
  46068. }
  46069. if ($that->hasBeenResolved() === false) {
  46070. return;
  46071. }
  46072. if ($that->ipsCount === $that->failureCount) {
  46073. $that->cleanUp();
  46074. $reject(new \RuntimeException(
  46075. $that->error(),
  46076. $e->getCode(),
  46077. $e
  46078. ));
  46079. }
  46080. });
  46081. if ($this->nextAttemptTimer === null && (\count($this->connectQueue) > 0 || $this->resolved[Message::TYPE_A] === false || $this->resolved[Message::TYPE_AAAA] === false)) {
  46082. $this->nextAttemptTimer = $this->loop->addTimer(self::CONNECTION_ATTEMPT_DELAY, function () use ($that, $resolve, $reject) {
  46083. $that->nextAttemptTimer = null;
  46084. if ($that->connectQueue) {
  46085. $that->check($resolve, $reject);
  46086. }
  46087. });
  46088. }
  46089. }
  46090. public function attemptConnection($ip)
  46091. {
  46092. $uri = Connector::uri($this->parts, $this->host, $ip);
  46093. return $this->connector->connect($uri);
  46094. }
  46095. public function cleanUp()
  46096. {
  46097. $this->connectQueue = array();
  46098. foreach ($this->connectionPromises as $connectionPromise) {
  46099. if ($connectionPromise instanceof PromiseInterface && \method_exists($connectionPromise, 'cancel')) {
  46100. $connectionPromise->cancel();
  46101. }
  46102. }
  46103. foreach (\array_reverse($this->resolverPromises) as $resolverPromise) {
  46104. if ($resolverPromise instanceof PromiseInterface && \method_exists($resolverPromise, 'cancel')) {
  46105. $resolverPromise->cancel();
  46106. }
  46107. }
  46108. if ($this->nextAttemptTimer instanceof TimerInterface) {
  46109. $this->loop->cancelTimer($this->nextAttemptTimer);
  46110. $this->nextAttemptTimer = null;
  46111. }
  46112. }
  46113. public function hasBeenResolved()
  46114. {
  46115. foreach ($this->resolved as $typeHasBeenResolved) {
  46116. if ($typeHasBeenResolved === false) {
  46117. return false;
  46118. }
  46119. }
  46120. return true;
  46121. }
  46122. public function mixIpsIntoConnectQueue(array $ips)
  46123. {
  46124. \shuffle($ips);
  46125. $this->ipsCount += \count($ips);
  46126. $connectQueueStash = $this->connectQueue;
  46127. $this->connectQueue = array();
  46128. while (\count($connectQueueStash) > 0 || \count($ips) > 0) {
  46129. if (\count($ips) > 0) {
  46130. $this->connectQueue[] = \array_shift($ips);
  46131. }
  46132. if (\count($connectQueueStash) > 0) {
  46133. $this->connectQueue[] = \array_shift($connectQueueStash);
  46134. }
  46135. }
  46136. }
  46137. public function error()
  46138. {
  46139. if ($this->lastError4 === $this->lastError6) {
  46140. $message = $this->lastError6;
  46141. } elseif ($this->lastErrorFamily === 6) {
  46142. $message = 'Last error for IPv6: ' . $this->lastError6 . '. Previous error for IPv4: ' . $this->lastError4;
  46143. } else {
  46144. $message = 'Last error for IPv4: ' . $this->lastError4 . '. Previous error for IPv6: ' . $this->lastError6;
  46145. }
  46146. if ($this->hasBeenResolved() && $this->ipsCount === 0) {
  46147. if ($this->lastError6 === $this->lastError4) {
  46148. $message = ' during DNS lookup: ' . $this->lastError6;
  46149. } else {
  46150. $message = ' during DNS lookup. ' . $message;
  46151. }
  46152. } else {
  46153. $message = ': ' . $message;
  46154. }
  46155. return 'Connection to ' . $this->uri . ' failed' . $message;
  46156. }
  46157. }
  46158. <?php
  46159. namespace React\Socket;
  46160. use Evenement\EventEmitter;
  46161. use React\EventLoop\Loop;
  46162. use React\EventLoop\LoopInterface;
  46163. use InvalidArgumentException;
  46164. use RuntimeException;
  46165. final class TcpServer extends EventEmitter implements ServerInterface
  46166. {
  46167. private $master;
  46168. private $loop;
  46169. private $listening = false;
  46170. public function __construct($uri, $loop = null, array $context = array())
  46171. {
  46172. if ($loop !== null && !$loop instanceof LoopInterface) {
  46173. throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
  46174. }
  46175. $this->loop = $loop ?: Loop::get();
  46176. if ((string)(int)$uri === (string)$uri) {
  46177. $uri = '127.0.0.1:' . $uri;
  46178. }
  46179. if (\strpos($uri, '://') === false) {
  46180. $uri = 'tcp://' . $uri;
  46181. }
  46182. if (\substr($uri, -2) === ':0') {
  46183. $parts = \parse_url(\substr($uri, 0, -2));
  46184. if ($parts) {
  46185. $parts['port'] = 0;
  46186. }
  46187. } else {
  46188. $parts = \parse_url($uri);
  46189. }
  46190. if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
  46191. throw new \InvalidArgumentException(
  46192. 'Invalid URI "' . $uri . '" given (EINVAL)',
  46193. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  46194. );
  46195. }
  46196. if (@\inet_pton(\trim($parts['host'], '[]')) === false) {
  46197. throw new \InvalidArgumentException(
  46198. 'Given URI "' . $uri . '" does not contain a valid host IP (EINVAL)',
  46199. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  46200. );
  46201. }
  46202. $this->master = @\stream_socket_server(
  46203. $uri,
  46204. $errno,
  46205. $errstr,
  46206. \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN,
  46207. \stream_context_create(array('socket' => $context + array('backlog' => 511)))
  46208. );
  46209. if (false === $this->master) {
  46210. if ($errno === 0) {
  46211. $errno = SocketServer::errno($errstr);
  46212. }
  46213. throw new \RuntimeException(
  46214. 'Failed to listen on "' . $uri . '": ' . $errstr . SocketServer::errconst($errno),
  46215. $errno
  46216. );
  46217. }
  46218. \stream_set_blocking($this->master, false);
  46219. $this->resume();
  46220. }
  46221. public function getAddress()
  46222. {
  46223. if (!\is_resource($this->master)) {
  46224. return null;
  46225. }
  46226. $address = \stream_socket_get_name($this->master, false);
  46227. $pos = \strrpos($address, ':');
  46228. if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
  46229. $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1);
  46230. }
  46231. return 'tcp://' . $address;
  46232. }
  46233. public function pause()
  46234. {
  46235. if (!$this->listening) {
  46236. return;
  46237. }
  46238. $this->loop->removeReadStream($this->master);
  46239. $this->listening = false;
  46240. }
  46241. public function resume()
  46242. {
  46243. if ($this->listening || !\is_resource($this->master)) {
  46244. return;
  46245. }
  46246. $that = $this;
  46247. $this->loop->addReadStream($this->master, function ($master) use ($that) {
  46248. try {
  46249. $newSocket = SocketServer::accept($master);
  46250. } catch (\RuntimeException $e) {
  46251. $that->emit('error', array($e));
  46252. return;
  46253. }
  46254. $that->handleConnection($newSocket);
  46255. });
  46256. $this->listening = true;
  46257. }
  46258. public function close()
  46259. {
  46260. if (!\is_resource($this->master)) {
  46261. return;
  46262. }
  46263. $this->pause();
  46264. \fclose($this->master);
  46265. $this->removeAllListeners();
  46266. }
  46267. public function handleConnection($socket)
  46268. {
  46269. $this->emit('connection', array(
  46270. new Connection($socket, $this->loop)
  46271. ));
  46272. }
  46273. }
  46274. <?php
  46275. namespace React\Socket;
  46276. use React\EventLoop\Loop;
  46277. use React\EventLoop\LoopInterface;
  46278. use React\Promise\Promise;
  46279. final class TimeoutConnector implements ConnectorInterface
  46280. {
  46281. private $connector;
  46282. private $timeout;
  46283. private $loop;
  46284. public function __construct(ConnectorInterface $connector, $timeout, $loop = null)
  46285. {
  46286. if ($loop !== null && !$loop instanceof LoopInterface) {
  46287. throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
  46288. }
  46289. $this->connector = $connector;
  46290. $this->timeout = $timeout;
  46291. $this->loop = $loop ?: Loop::get();
  46292. }
  46293. public function connect($uri)
  46294. {
  46295. $promise = $this->connector->connect($uri);
  46296. $loop = $this->loop;
  46297. $time = $this->timeout;
  46298. return new Promise(function ($resolve, $reject) use ($loop, $time, $promise, $uri) {
  46299. $timer = null;
  46300. $promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
  46301. if ($timer) {
  46302. $loop->cancelTimer($timer);
  46303. }
  46304. $timer = false;
  46305. $resolve($v);
  46306. }, function ($v) use (&$timer, $loop, $reject) {
  46307. if ($timer) {
  46308. $loop->cancelTimer($timer);
  46309. }
  46310. $timer = false;
  46311. $reject($v);
  46312. });
  46313. if ($timer === false) {
  46314. return;
  46315. }
  46316. $timer = $loop->addTimer($time, function () use ($time, &$promise, $reject, $uri) {
  46317. $reject(new \RuntimeException(
  46318. 'Connection to ' . $uri . ' timed out after ' . $time . ' seconds (ETIMEDOUT)',
  46319. \defined('SOCKET_ETIMEDOUT') ? \SOCKET_ETIMEDOUT : 110
  46320. ));
  46321. assert(\method_exists($promise, 'cancel'));
  46322. $promise->cancel();
  46323. $promise = null;
  46324. });
  46325. }, function () use (&$promise) {
  46326. assert(\method_exists($promise, 'cancel'));
  46327. $promise->cancel();
  46328. $promise = null;
  46329. });
  46330. }
  46331. }
  46332. <?php
  46333. namespace React\Socket;
  46334. use Evenement\EventEmitter;
  46335. use Exception;
  46336. use OverflowException;
  46337. class LimitingServer extends EventEmitter implements ServerInterface
  46338. {
  46339. private $connections = array();
  46340. private $server;
  46341. private $limit;
  46342. private $pauseOnLimit = false;
  46343. private $autoPaused = false;
  46344. private $manuPaused = false;
  46345. public function __construct(ServerInterface $server, $connectionLimit, $pauseOnLimit = false)
  46346. {
  46347. $this->server = $server;
  46348. $this->limit = $connectionLimit;
  46349. if ($connectionLimit !== null) {
  46350. $this->pauseOnLimit = $pauseOnLimit;
  46351. }
  46352. $this->server->on('connection', array($this, 'handleConnection'));
  46353. $this->server->on('error', array($this, 'handleError'));
  46354. }
  46355. public function getConnections()
  46356. {
  46357. return $this->connections;
  46358. }
  46359. public function getAddress()
  46360. {
  46361. return $this->server->getAddress();
  46362. }
  46363. public function pause()
  46364. {
  46365. if (!$this->manuPaused) {
  46366. $this->manuPaused = true;
  46367. if (!$this->autoPaused) {
  46368. $this->server->pause();
  46369. }
  46370. }
  46371. }
  46372. public function resume()
  46373. {
  46374. if ($this->manuPaused) {
  46375. $this->manuPaused = false;
  46376. if (!$this->autoPaused) {
  46377. $this->server->resume();
  46378. }
  46379. }
  46380. }
  46381. public function close()
  46382. {
  46383. $this->server->close();
  46384. }
  46385. public function handleConnection(ConnectionInterface $connection)
  46386. {
  46387. if ($this->limit !== null && \count($this->connections) >= $this->limit) {
  46388. $this->handleError(new \OverflowException('Connection closed because server reached connection limit'));
  46389. $connection->close();
  46390. return;
  46391. }
  46392. $this->connections[] = $connection;
  46393. $that = $this;
  46394. $connection->on('close', function () use ($that, $connection) {
  46395. $that->handleDisconnection($connection);
  46396. });
  46397. if ($this->pauseOnLimit && !$this->autoPaused && \count($this->connections) >= $this->limit) {
  46398. $this->autoPaused = true;
  46399. if (!$this->manuPaused) {
  46400. $this->server->pause();
  46401. }
  46402. }
  46403. $this->emit('connection', array($connection));
  46404. }
  46405. public function handleDisconnection(ConnectionInterface $connection)
  46406. {
  46407. unset($this->connections[\array_search($connection, $this->connections)]);
  46408. if ($this->autoPaused && \count($this->connections) < $this->limit) {
  46409. $this->autoPaused = false;
  46410. if (!$this->manuPaused) {
  46411. $this->server->resume();
  46412. }
  46413. }
  46414. }
  46415. public function handleError(\Exception $error)
  46416. {
  46417. $this->emit('error', array($error));
  46418. }
  46419. }
  46420. <?php
  46421. namespace React\Socket;
  46422. use React\Dns\Config\Config as DnsConfig;
  46423. use React\Dns\Resolver\Factory as DnsFactory;
  46424. use React\Dns\Resolver\ResolverInterface;
  46425. use React\EventLoop\LoopInterface;
  46426. final class Connector implements ConnectorInterface
  46427. {
  46428. private $connectors = array();
  46429. public function __construct($context = array(), $loop = null)
  46430. {
  46431. if (($context instanceof LoopInterface || $context === null) && (\func_num_args() <= 1 || \is_array($loop))) {
  46432. $swap = $loop === null ? array(): $loop;
  46433. $loop = $context;
  46434. $context = $swap;
  46435. }
  46436. if (!\is_array($context) || ($loop !== null && !$loop instanceof LoopInterface)) {
  46437. throw new \InvalidArgumentException('Expected "array $context" and "?LoopInterface $loop" arguments');
  46438. }
  46439. $context += array(
  46440. 'tcp' => true,
  46441. 'tls' => true,
  46442. 'unix' => true,
  46443. 'dns' => true,
  46444. 'timeout' => true,
  46445. 'happy_eyeballs' => true,
  46446. );
  46447. if ($context['timeout'] === true) {
  46448. $context['timeout'] = (float)\ini_get("default_socket_timeout");
  46449. }
  46450. if ($context['tcp'] instanceof ConnectorInterface) {
  46451. $tcp = $context['tcp'];
  46452. } else {
  46453. $tcp = new TcpConnector(
  46454. $loop,
  46455. \is_array($context['tcp']) ? $context['tcp'] : array()
  46456. );
  46457. }
  46458. if ($context['dns'] !== false) {
  46459. if ($context['dns'] instanceof ResolverInterface) {
  46460. $resolver = $context['dns'];
  46461. } else {
  46462. if ($context['dns'] !== true) {
  46463. $config = $context['dns'];
  46464. } else {
  46465. $config = DnsConfig::loadSystemConfigBlocking();
  46466. if (!$config->nameservers) {
  46467. $config->nameservers[] = '8.8.8.8';
  46468. }
  46469. }
  46470. $factory = new DnsFactory();
  46471. $resolver = $factory->createCached(
  46472. $config,
  46473. $loop
  46474. );
  46475. }
  46476. if ($context['happy_eyeballs'] === true) {
  46477. $tcp = new HappyEyeBallsConnector($loop, $tcp, $resolver);
  46478. } else {
  46479. $tcp = new DnsConnector($tcp, $resolver);
  46480. }
  46481. }
  46482. if ($context['tcp'] !== false) {
  46483. $context['tcp'] = $tcp;
  46484. if ($context['timeout'] !== false) {
  46485. $context['tcp'] = new TimeoutConnector(
  46486. $context['tcp'],
  46487. $context['timeout'],
  46488. $loop
  46489. );
  46490. }
  46491. $this->connectors['tcp'] = $context['tcp'];
  46492. }
  46493. if ($context['tls'] !== false) {
  46494. if (!$context['tls'] instanceof ConnectorInterface) {
  46495. $context['tls'] = new SecureConnector(
  46496. $tcp,
  46497. $loop,
  46498. \is_array($context['tls']) ? $context['tls'] : array()
  46499. );
  46500. }
  46501. if ($context['timeout'] !== false) {
  46502. $context['tls'] = new TimeoutConnector(
  46503. $context['tls'],
  46504. $context['timeout'],
  46505. $loop
  46506. );
  46507. }
  46508. $this->connectors['tls'] = $context['tls'];
  46509. }
  46510. if ($context['unix'] !== false) {
  46511. if (!$context['unix'] instanceof ConnectorInterface) {
  46512. $context['unix'] = new UnixConnector($loop);
  46513. }
  46514. $this->connectors['unix'] = $context['unix'];
  46515. }
  46516. }
  46517. public function connect($uri)
  46518. {
  46519. $scheme = 'tcp';
  46520. if (\strpos($uri, '://') !== false) {
  46521. $scheme = (string)\substr($uri, 0, \strpos($uri, '://'));
  46522. }
  46523. if (!isset($this->connectors[$scheme])) {
  46524. return \React\Promise\reject(new \RuntimeException(
  46525. 'No connector available for URI scheme "' . $scheme . '" (EINVAL)',
  46526. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  46527. ));
  46528. }
  46529. return $this->connectors[$scheme]->connect($uri);
  46530. }
  46531. public static function uri(array $parts, $host, $ip)
  46532. {
  46533. $uri = '';
  46534. if (isset($parts['scheme'])) {
  46535. $uri .= $parts['scheme'] . '://';
  46536. }
  46537. if (\strpos($ip, ':') !== false) {
  46538. $uri .= '[' . $ip . ']';
  46539. } else {
  46540. $uri .= $ip;
  46541. }
  46542. if (isset($parts['port'])) {
  46543. $uri .= ':' . $parts['port'];
  46544. }
  46545. if (isset($parts['path'])) {
  46546. $uri .= $parts['path'];
  46547. }
  46548. if (isset($parts['query'])) {
  46549. $uri .= '?' . $parts['query'];
  46550. }
  46551. $args = array();
  46552. \parse_str(isset($parts['query']) ? $parts['query'] : '', $args);
  46553. if ($host !== $ip && !isset($args['hostname'])) {
  46554. $uri .= (isset($parts['query']) ? '&' : '?') . 'hostname=' . \rawurlencode($host);
  46555. }
  46556. if (isset($parts['fragment'])) {
  46557. $uri .= '#' . $parts['fragment'];
  46558. }
  46559. return $uri;
  46560. }
  46561. }
  46562. <?php
  46563. namespace React\Socket;
  46564. use Evenement\EventEmitterInterface;
  46565. interface ServerInterface extends EventEmitterInterface
  46566. {
  46567. public function getAddress();
  46568. public function pause();
  46569. public function resume();
  46570. public function close();
  46571. }
  46572. <?php
  46573. namespace React\Socket;
  46574. use Evenement\EventEmitter;
  46575. use React\EventLoop\LoopInterface;
  46576. final class SocketServer extends EventEmitter implements ServerInterface
  46577. {
  46578. private $server;
  46579. public function __construct($uri, array $context = array(), $loop = null)
  46580. {
  46581. if ($loop !== null && !$loop instanceof LoopInterface) {
  46582. throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
  46583. }
  46584. $context += array(
  46585. 'tcp' => array(),
  46586. 'tls' => array(),
  46587. 'unix' => array()
  46588. );
  46589. $scheme = 'tcp';
  46590. $pos = \strpos($uri, '://');
  46591. if ($pos !== false) {
  46592. $scheme = \substr($uri, 0, $pos);
  46593. }
  46594. if ($scheme === 'unix') {
  46595. $server = new UnixServer($uri, $loop, $context['unix']);
  46596. } elseif ($scheme === 'php') {
  46597. $server = new FdServer($uri, $loop);
  46598. } else {
  46599. if (preg_match('#^(?:\w+://)?\d+$#', $uri)) {
  46600. throw new \InvalidArgumentException(
  46601. 'Invalid URI given (EINVAL)',
  46602. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  46603. );
  46604. }
  46605. $server = new TcpServer(str_replace('tls://', '', $uri), $loop, $context['tcp']);
  46606. if ($scheme === 'tls') {
  46607. $server = new SecureServer($server, $loop, $context['tls']);
  46608. }
  46609. }
  46610. $this->server = $server;
  46611. $that = $this;
  46612. $server->on('connection', function (ConnectionInterface $conn) use ($that) {
  46613. $that->emit('connection', array($conn));
  46614. });
  46615. $server->on('error', function (\Exception $error) use ($that) {
  46616. $that->emit('error', array($error));
  46617. });
  46618. }
  46619. public function getAddress()
  46620. {
  46621. return $this->server->getAddress();
  46622. }
  46623. public function pause()
  46624. {
  46625. $this->server->pause();
  46626. }
  46627. public function resume()
  46628. {
  46629. $this->server->resume();
  46630. }
  46631. public function close()
  46632. {
  46633. $this->server->close();
  46634. }
  46635. public static function accept($socket)
  46636. {
  46637. $errno = 0;
  46638. $errstr = '';
  46639. \set_error_handler(function ($_, $error) use (&$errno, &$errstr) {
  46640. $errstr = \preg_replace('#.*: #', '', $error);
  46641. $errno = SocketServer::errno($errstr);
  46642. });
  46643. $newSocket = \stream_socket_accept($socket, 0);
  46644. \restore_error_handler();
  46645. if (false === $newSocket) {
  46646. throw new \RuntimeException(
  46647. 'Unable to accept new connection: ' . $errstr . self::errconst($errno),
  46648. $errno
  46649. );
  46650. }
  46651. return $newSocket;
  46652. }
  46653. public static function errno($errstr)
  46654. {
  46655. $strerror = \function_exists('socket_strerror') ? 'socket_strerror' : (\function_exists('posix_strerror') ? 'posix_strerror' : (\function_exists('pcntl_strerror') ? 'pcntl_strerror' : null));
  46656. if ($strerror !== null) {
  46657. assert(\is_string($strerror) && \is_callable($strerror));
  46658. foreach (\get_defined_constants(false) as $name => $value) {
  46659. if (\is_int($value) && (\strpos($name, 'SOCKET_E') === 0 || \strpos($name, 'PCNTL_E') === 0) && $strerror($value) === $errstr) {
  46660. return $value;
  46661. }
  46662. }
  46663. for ($errno = 1, $max = \defined('MAX_ERRNO') ? \MAX_ERRNO : 4095; $errno <= $max; ++$errno) {
  46664. if ($strerror($errno) === $errstr) {
  46665. return $errno;
  46666. }
  46667. }
  46668. }
  46669. return 0;
  46670. }
  46671. public static function errconst($errno)
  46672. {
  46673. foreach (\get_defined_constants(false) as $name => $value) {
  46674. if ($value === $errno && (\strpos($name, 'SOCKET_E') === 0 || \strpos($name, 'PCNTL_E') === 0)) {
  46675. return ' (' . \substr($name, \strpos($name, '_') + 1) . ')';
  46676. }
  46677. }
  46678. return '';
  46679. }
  46680. }
  46681. <?php
  46682. namespace React\Socket;
  46683. use React\Dns\Resolver\ResolverInterface;
  46684. use React\EventLoop\Loop;
  46685. use React\EventLoop\LoopInterface;
  46686. use React\Promise;
  46687. final class HappyEyeBallsConnector implements ConnectorInterface
  46688. {
  46689. private $loop;
  46690. private $connector;
  46691. private $resolver;
  46692. public function __construct($loop = null, $connector = null, $resolver = null)
  46693. {
  46694. if ($loop !== null && !$loop instanceof LoopInterface) {
  46695. throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
  46696. }
  46697. if (!$connector instanceof ConnectorInterface) {
  46698. throw new \InvalidArgumentException('Argument #2 ($connector) expected React\Socket\ConnectorInterface');
  46699. }
  46700. if (!$resolver instanceof ResolverInterface) {
  46701. throw new \InvalidArgumentException('Argument #3 ($resolver) expected React\Dns\Resolver\ResolverInterface');
  46702. }
  46703. $this->loop = $loop ?: Loop::get();
  46704. $this->connector = $connector;
  46705. $this->resolver = $resolver;
  46706. }
  46707. public function connect($uri)
  46708. {
  46709. $original = $uri;
  46710. if (\strpos($uri, '://') === false) {
  46711. $uri = 'tcp://' . $uri;
  46712. $parts = \parse_url($uri);
  46713. if (isset($parts['scheme'])) {
  46714. unset($parts['scheme']);
  46715. }
  46716. } else {
  46717. $parts = \parse_url($uri);
  46718. }
  46719. if (!$parts || !isset($parts['host'])) {
  46720. return Promise\reject(new \InvalidArgumentException(
  46721. 'Given URI "' . $original . '" is invalid (EINVAL)',
  46722. \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : (\defined('PCNTL_EINVAL') ? \PCNTL_EINVAL : 22)
  46723. ));
  46724. }
  46725. $host = \trim($parts['host'], '[]');
  46726. if (@\inet_pton($host) !== false) {
  46727. return $this->connector->connect($original);
  46728. }
  46729. $builder = new HappyEyeBallsConnectionBuilder(
  46730. $this->loop,
  46731. $this->connector,
  46732. $this->resolver,
  46733. $uri,
  46734. $host,
  46735. $parts
  46736. );
  46737. return $builder->connect();
  46738. }
  46739. }
  46740. <?php
  46741. namespace React\Socket;
  46742. interface ConnectorInterface
  46743. {
  46744. public function connect($uri);
  46745. }
  46746. <?php
  46747. namespace React\ChildProcess;
  46748. use Evenement\EventEmitter;
  46749. use React\EventLoop\Loop;
  46750. use React\EventLoop\LoopInterface;
  46751. use React\Stream\ReadableResourceStream;
  46752. use React\Stream\ReadableStreamInterface;
  46753. use React\Stream\WritableResourceStream;
  46754. use React\Stream\WritableStreamInterface;
  46755. use React\Stream\DuplexResourceStream;
  46756. use React\Stream\DuplexStreamInterface;
  46757. class Process extends EventEmitter
  46758. {
  46759. public $stdin;
  46760. public $stdout;
  46761. public $stderr;
  46762. public $pipes = array();
  46763. private $cmd;
  46764. private $cwd;
  46765. private $env;
  46766. private $fds;
  46767. private $enhanceSigchildCompatibility;
  46768. private $sigchildPipe;
  46769. private $process;
  46770. private $status;
  46771. private $exitCode;
  46772. private $fallbackExitCode;
  46773. private $stopSignal;
  46774. private $termSignal;
  46775. private static $sigchild;
  46776. public function __construct($cmd, $cwd = null, $env = null, $fds = null)
  46777. {
  46778. if ($env !== null && !\is_array($env)) {
  46779. throw new \InvalidArgumentException('Argument #3 ($env) expected null|array');
  46780. }
  46781. if ($fds !== null && !\is_array($fds)) {
  46782. throw new \InvalidArgumentException('Argument #4 ($fds) expected null|array');
  46783. }
  46784. if (!\function_exists('proc_open')) {
  46785. throw new \LogicException('The Process class relies on proc_open(), which is not available on your PHP installation.');
  46786. }
  46787. $this->cmd = $cmd;
  46788. $this->cwd = $cwd;
  46789. if (null !== $env) {
  46790. $this->env = array();
  46791. foreach ($env as $key => $value) {
  46792. $this->env[(binary) $key] = (binary) $value;
  46793. }
  46794. }
  46795. if ($fds === null) {
  46796. $fds = array(
  46797. array('pipe', 'r'),
  46798. array('pipe', 'w'),
  46799. array('pipe', 'w'),
  46800. );
  46801. }
  46802. if (\DIRECTORY_SEPARATOR === '\\') {
  46803. foreach ($fds as $fd) {
  46804. if (isset($fd[0]) && $fd[0] === 'pipe') {
  46805. throw new \LogicException('Process pipes are not supported on Windows due to their blocking nature on Windows');
  46806. }
  46807. }
  46808. }
  46809. $this->fds = $fds;
  46810. $this->enhanceSigchildCompatibility = self::isSigchildEnabled();
  46811. }
  46812. public function start($loop = null, $interval = 0.1)
  46813. {
  46814. if ($loop !== null && !$loop instanceof LoopInterface) {
  46815. throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
  46816. }
  46817. if ($this->isRunning()) {
  46818. throw new \RuntimeException('Process is already running');
  46819. }
  46820. $loop = $loop ?: Loop::get();
  46821. $cmd = $this->cmd;
  46822. $fdSpec = $this->fds;
  46823. $sigchild = null;
  46824. if ($this->enhanceSigchildCompatibility) {
  46825. $fdSpec[] = array('pipe', 'w');
  46826. \end($fdSpec);
  46827. $sigchild = \key($fdSpec);
  46828. if ($sigchild < 3) {
  46829. $fdSpec[3] = $fdSpec[$sigchild];
  46830. unset($fdSpec[$sigchild]);
  46831. $sigchild = 3;
  46832. }
  46833. $cmd = \sprintf('(%s) ' . $sigchild . '>/dev/null; code=$?; echo $code >&' . $sigchild . '; exit $code', $cmd);
  46834. }
  46835. $options = array();
  46836. if (\DIRECTORY_SEPARATOR === '\\') {
  46837. $options['bypass_shell'] = true;
  46838. $options['suppress_errors'] = true;
  46839. }
  46840. $errstr = '';
  46841. \set_error_handler(function ($_, $error) use (&$errstr) {
  46842. $errstr = $error;
  46843. });
  46844. $pipes = array();
  46845. $this->process = @\proc_open($cmd, $fdSpec, $pipes, $this->cwd, $this->env, $options);
  46846. \restore_error_handler();
  46847. if (!\is_resource($this->process)) {
  46848. throw new \RuntimeException('Unable to launch a new process: ' . $errstr);
  46849. }
  46850. $that = $this;
  46851. $closeCount = 0;
  46852. $streamCloseHandler = function () use (&$closeCount, $loop, $interval, $that) {
  46853. $closeCount--;
  46854. if ($closeCount > 0) {
  46855. return;
  46856. }
  46857. if (!$that->isRunning()) {
  46858. $that->close();
  46859. $that->emit('exit', array($that->getExitCode(), $that->getTermSignal()));
  46860. return;
  46861. }
  46862. $loop->addPeriodicTimer($interval, function ($timer) use ($that, $loop) {
  46863. if (!$that->isRunning()) {
  46864. $loop->cancelTimer($timer);
  46865. $that->close();
  46866. $that->emit('exit', array($that->getExitCode(), $that->getTermSignal()));
  46867. }
  46868. });
  46869. };
  46870. if ($sigchild !== null) {
  46871. $this->sigchildPipe = $pipes[$sigchild];
  46872. unset($pipes[$sigchild]);
  46873. }
  46874. foreach ($pipes as $n => $fd) {
  46875. $meta = \stream_get_meta_data($fd);
  46876. $mode = $meta['mode'] === '' ? ($this->fds[$n][1] === 'r' ? 'w' : 'r') : $meta['mode'];
  46877. if ($mode === 'r+') {
  46878. $stream = new DuplexResourceStream($fd, $loop);
  46879. $stream->on('close', $streamCloseHandler);
  46880. $closeCount++;
  46881. } elseif ($mode === 'w') {
  46882. $stream = new WritableResourceStream($fd, $loop);
  46883. } else {
  46884. $stream = new ReadableResourceStream($fd, $loop);
  46885. $stream->on('close', $streamCloseHandler);
  46886. $closeCount++;
  46887. }
  46888. $this->pipes[$n] = $stream;
  46889. }
  46890. $this->stdin = isset($this->pipes[0]) ? $this->pipes[0] : null;
  46891. $this->stdout = isset($this->pipes[1]) ? $this->pipes[1] : null;
  46892. $this->stderr = isset($this->pipes[2]) ? $this->pipes[2] : null;
  46893. if (!$closeCount) {
  46894. $streamCloseHandler();
  46895. }
  46896. }
  46897. public function close()
  46898. {
  46899. if ($this->process === null) {
  46900. return;
  46901. }
  46902. foreach ($this->pipes as $pipe) {
  46903. $pipe->close();
  46904. }
  46905. if ($this->enhanceSigchildCompatibility) {
  46906. $this->pollExitCodePipe();
  46907. $this->closeExitCodePipe();
  46908. }
  46909. $exitCode = \proc_close($this->process);
  46910. $this->process = null;
  46911. if ($this->exitCode === null && $exitCode !== -1) {
  46912. $this->exitCode = $exitCode;
  46913. }
  46914. if ($this->exitCode === null && $this->status['exitcode'] !== -1) {
  46915. $this->exitCode = $this->status['exitcode'];
  46916. }
  46917. if ($this->exitCode === null && $this->fallbackExitCode !== null) {
  46918. $this->exitCode = $this->fallbackExitCode;
  46919. $this->fallbackExitCode = null;
  46920. }
  46921. }
  46922. public function terminate($signal = null)
  46923. {
  46924. if ($this->process === null) {
  46925. return false;
  46926. }
  46927. if ($signal !== null) {
  46928. return \proc_terminate($this->process, $signal);
  46929. }
  46930. return \proc_terminate($this->process);
  46931. }
  46932. public function getCommand()
  46933. {
  46934. return $this->cmd;
  46935. }
  46936. public function getExitCode()
  46937. {
  46938. return $this->exitCode;
  46939. }
  46940. public function getPid()
  46941. {
  46942. $status = $this->getCachedStatus();
  46943. return $status !== null ? $status['pid'] : null;
  46944. }
  46945. public function getStopSignal()
  46946. {
  46947. return $this->stopSignal;
  46948. }
  46949. public function getTermSignal()
  46950. {
  46951. return $this->termSignal;
  46952. }
  46953. public function isRunning()
  46954. {
  46955. if ($this->process === null) {
  46956. return false;
  46957. }
  46958. $status = $this->getFreshStatus();
  46959. return $status !== null ? $status['running'] : false;
  46960. }
  46961. public function isStopped()
  46962. {
  46963. $status = $this->getFreshStatus();
  46964. return $status !== null ? $status['stopped'] : false;
  46965. }
  46966. public function isTerminated()
  46967. {
  46968. $status = $this->getFreshStatus();
  46969. return $status !== null ? $status['signaled'] : false;
  46970. }
  46971. public final static function isSigchildEnabled()
  46972. {
  46973. if (null !== self::$sigchild) {
  46974. return self::$sigchild;
  46975. }
  46976. if (!\function_exists('phpinfo')) {
  46977. return self::$sigchild = false;
  46978. }
  46979. \ob_start();
  46980. \phpinfo(INFO_GENERAL);
  46981. return self::$sigchild = false !== \strpos(\ob_get_clean(), '--enable-sigchild');
  46982. }
  46983. public final static function setSigchildEnabled($sigchild)
  46984. {
  46985. self::$sigchild = (bool) $sigchild;
  46986. }
  46987. private function pollExitCodePipe()
  46988. {
  46989. if ($this->sigchildPipe === null) {
  46990. return;
  46991. }
  46992. $r = array($this->sigchildPipe);
  46993. $w = $e = null;
  46994. $n = @\stream_select($r, $w, $e, 0);
  46995. if (1 !== $n) {
  46996. return;
  46997. }
  46998. $data = \fread($r[0], 8192);
  46999. if (\strlen($data) > 0) {
  47000. $this->fallbackExitCode = (int) $data;
  47001. }
  47002. }
  47003. private function closeExitCodePipe()
  47004. {
  47005. if ($this->sigchildPipe === null) {
  47006. return;
  47007. }
  47008. \fclose($this->sigchildPipe);
  47009. $this->sigchildPipe = null;
  47010. }
  47011. private function getCachedStatus()
  47012. {
  47013. if ($this->status === null) {
  47014. $this->updateStatus();
  47015. }
  47016. return $this->status;
  47017. }
  47018. private function getFreshStatus()
  47019. {
  47020. $this->updateStatus();
  47021. return $this->status;
  47022. }
  47023. private function updateStatus()
  47024. {
  47025. if ($this->process === null) {
  47026. return;
  47027. }
  47028. $this->status = \proc_get_status($this->process);
  47029. if ($this->status === false) {
  47030. throw new \UnexpectedValueException('proc_get_status() failed');
  47031. }
  47032. if ($this->status['stopped']) {
  47033. $this->stopSignal = $this->status['stopsig'];
  47034. }
  47035. if ($this->status['signaled']) {
  47036. $this->termSignal = $this->status['termsig'];
  47037. }
  47038. if (!$this->status['running'] && -1 !== $this->status['exitcode']) {
  47039. $this->exitCode = $this->status['exitcode'];
  47040. }
  47041. }
  47042. }
  47043. <?php declare(strict_types=1);
  47044. namespace SebastianBergmann\Diff;
  47045. final class Diff
  47046. {
  47047. private $from;
  47048. private $to;
  47049. private $chunks;
  47050. public function __construct(string $from, string $to, array $chunks = [])
  47051. {
  47052. $this->from = $from;
  47053. $this->to = $to;
  47054. $this->chunks = $chunks;
  47055. }
  47056. public function getFrom(): string
  47057. {
  47058. return $this->from;
  47059. }
  47060. public function getTo(): string
  47061. {
  47062. return $this->to;
  47063. }
  47064. public function getChunks(): array
  47065. {
  47066. return $this->chunks;
  47067. }
  47068. public function setChunks(array $chunks): void
  47069. {
  47070. $this->chunks = $chunks;
  47071. }
  47072. }
  47073. <?php declare(strict_types=1);
  47074. namespace SebastianBergmann\Diff;
  47075. use function array_pop;
  47076. use function count;
  47077. use function max;
  47078. use function preg_match;
  47079. use function preg_split;
  47080. final class Parser
  47081. {
  47082. public function parse(string $string): array
  47083. {
  47084. $lines = preg_split('(\r\n|\r|\n)', $string);
  47085. if (!empty($lines) && $lines[count($lines) - 1] === '') {
  47086. array_pop($lines);
  47087. }
  47088. $lineCount = count($lines);
  47089. $diffs = [];
  47090. $diff = null;
  47091. $collected = [];
  47092. for ($i = 0; $i < $lineCount; ++$i) {
  47093. if (preg_match('#^---\h+"?(?P<file>[^\\v\\t"]+)#', $lines[$i], $fromMatch) &&
  47094. preg_match('#^\\+\\+\\+\\h+"?(?P<file>[^\\v\\t"]+)#', $lines[$i + 1], $toMatch)) {
  47095. if ($diff !== null) {
  47096. $this->parseFileDiff($diff, $collected);
  47097. $diffs[] = $diff;
  47098. $collected = [];
  47099. }
  47100. $diff = new Diff($fromMatch['file'], $toMatch['file']);
  47101. ++$i;
  47102. } else {
  47103. if (preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) {
  47104. continue;
  47105. }
  47106. $collected[] = $lines[$i];
  47107. }
  47108. }
  47109. if ($diff !== null && count($collected)) {
  47110. $this->parseFileDiff($diff, $collected);
  47111. $diffs[] = $diff;
  47112. }
  47113. return $diffs;
  47114. }
  47115. private function parseFileDiff(Diff $diff, array $lines): void
  47116. {
  47117. $chunks = [];
  47118. $chunk = null;
  47119. $diffLines = [];
  47120. foreach ($lines as $line) {
  47121. if (preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {
  47122. $chunk = new Chunk(
  47123. (int) $match['start'],
  47124. isset($match['startrange']) ? max(1, (int) $match['startrange']) : 1,
  47125. (int) $match['end'],
  47126. isset($match['endrange']) ? max(1, (int) $match['endrange']) : 1
  47127. );
  47128. $chunks[] = $chunk;
  47129. $diffLines = [];
  47130. continue;
  47131. }
  47132. if (preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) {
  47133. $type = Line::UNCHANGED;
  47134. if ($match['type'] === '+') {
  47135. $type = Line::ADDED;
  47136. } elseif ($match['type'] === '-') {
  47137. $type = Line::REMOVED;
  47138. }
  47139. $diffLines[] = new Line($type, $match['line']);
  47140. if (null !== $chunk) {
  47141. $chunk->setLines($diffLines);
  47142. }
  47143. }
  47144. }
  47145. $diff->setChunks($chunks);
  47146. }
  47147. }
  47148. <?php declare(strict_types=1);
  47149. namespace SebastianBergmann\Diff;
  47150. use function array_reverse;
  47151. use function count;
  47152. use function max;
  47153. use SplFixedArray;
  47154. final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  47155. {
  47156. public function calculate(array $from, array $to): array
  47157. {
  47158. $common = [];
  47159. $fromLength = count($from);
  47160. $toLength = count($to);
  47161. $width = $fromLength + 1;
  47162. $matrix = new SplFixedArray($width * ($toLength + 1));
  47163. for ($i = 0; $i <= $fromLength; ++$i) {
  47164. $matrix[$i] = 0;
  47165. }
  47166. for ($j = 0; $j <= $toLength; ++$j) {
  47167. $matrix[$j * $width] = 0;
  47168. }
  47169. for ($i = 1; $i <= $fromLength; ++$i) {
  47170. for ($j = 1; $j <= $toLength; ++$j) {
  47171. $o = ($j * $width) + $i;
  47172. $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0;
  47173. if ($matrix[$o - 1] > $matrix[$o - $width]) {
  47174. if ($firstOrLast > $matrix[$o - 1]) {
  47175. $matrix[$o] = $firstOrLast;
  47176. } else {
  47177. $matrix[$o] = $matrix[$o - 1];
  47178. }
  47179. } else {
  47180. if ($firstOrLast > $matrix[$o - $width]) {
  47181. $matrix[$o] = $firstOrLast;
  47182. } else {
  47183. $matrix[$o] = $matrix[$o - $width];
  47184. }
  47185. }
  47186. }
  47187. }
  47188. $i = $fromLength;
  47189. $j = $toLength;
  47190. while ($i > 0 && $j > 0) {
  47191. if ($from[$i - 1] === $to[$j - 1]) {
  47192. $common[] = $from[$i - 1];
  47193. --$i;
  47194. --$j;
  47195. } else {
  47196. $o = ($j * $width) + $i;
  47197. if ($matrix[$o - $width] > $matrix[$o - 1]) {
  47198. --$j;
  47199. } else {
  47200. --$i;
  47201. }
  47202. }
  47203. }
  47204. return array_reverse($common);
  47205. }
  47206. }
  47207. <?php declare(strict_types=1);
  47208. namespace SebastianBergmann\Diff\Output;
  47209. use function fclose;
  47210. use function fopen;
  47211. use function fwrite;
  47212. use function stream_get_contents;
  47213. use function substr;
  47214. use SebastianBergmann\Diff\Differ;
  47215. final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface
  47216. {
  47217. private $header;
  47218. public function __construct(string $header = "--- Original\n+++ New\n")
  47219. {
  47220. $this->header = $header;
  47221. }
  47222. public function getDiff(array $diff): string
  47223. {
  47224. $buffer = fopen('php://memory', 'r+b');
  47225. if ('' !== $this->header) {
  47226. fwrite($buffer, $this->header);
  47227. if ("\n" !== substr($this->header, -1, 1)) {
  47228. fwrite($buffer, "\n");
  47229. }
  47230. }
  47231. foreach ($diff as $diffEntry) {
  47232. if ($diffEntry[1] === Differ::ADDED) {
  47233. fwrite($buffer, '+' . $diffEntry[0]);
  47234. } elseif ($diffEntry[1] === Differ::REMOVED) {
  47235. fwrite($buffer, '-' . $diffEntry[0]);
  47236. } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) {
  47237. fwrite($buffer, ' ' . $diffEntry[0]);
  47238. continue;
  47239. } else {
  47240. continue;
  47241. }
  47242. $lc = substr($diffEntry[0], -1);
  47243. if ($lc !== "\n" && $lc !== "\r") {
  47244. fwrite($buffer, "\n");
  47245. }
  47246. }
  47247. $diff = stream_get_contents($buffer, -1, 0);
  47248. fclose($buffer);
  47249. return $diff;
  47250. }
  47251. }
  47252. <?php declare(strict_types=1);
  47253. namespace SebastianBergmann\Diff\Output;
  47254. interface DiffOutputBuilderInterface
  47255. {
  47256. public function getDiff(array $diff): string;
  47257. }
  47258. <?php declare(strict_types=1);
  47259. namespace SebastianBergmann\Diff\Output;
  47260. use function array_splice;
  47261. use function count;
  47262. use function fclose;
  47263. use function fopen;
  47264. use function fwrite;
  47265. use function max;
  47266. use function min;
  47267. use function stream_get_contents;
  47268. use function strlen;
  47269. use function substr;
  47270. use SebastianBergmann\Diff\Differ;
  47271. final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
  47272. {
  47273. private $collapseRanges = true;
  47274. private $commonLineThreshold = 6;
  47275. private $contextLines = 3;
  47276. private $header;
  47277. private $addLineNumbers;
  47278. public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = false)
  47279. {
  47280. $this->header = $header;
  47281. $this->addLineNumbers = $addLineNumbers;
  47282. }
  47283. public function getDiff(array $diff): string
  47284. {
  47285. $buffer = fopen('php://memory', 'r+b');
  47286. if ('' !== $this->header) {
  47287. fwrite($buffer, $this->header);
  47288. if ("\n" !== substr($this->header, -1, 1)) {
  47289. fwrite($buffer, "\n");
  47290. }
  47291. }
  47292. if (0 !== count($diff)) {
  47293. $this->writeDiffHunks($buffer, $diff);
  47294. }
  47295. $diff = stream_get_contents($buffer, -1, 0);
  47296. fclose($buffer);
  47297. $last = substr($diff, -1);
  47298. return 0 !== strlen($diff) && "\n" !== $last && "\r" !== $last
  47299. ? $diff . "\n"
  47300. : $diff;
  47301. }
  47302. private function writeDiffHunks($output, array $diff): void
  47303. {
  47304. $upperLimit = count($diff);
  47305. if (0 === $diff[$upperLimit - 1][1]) {
  47306. $lc = substr($diff[$upperLimit - 1][0], -1);
  47307. if ("\n" !== $lc) {
  47308. array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  47309. }
  47310. } else {
  47311. $toFind = [1 => true, 2 => true];
  47312. for ($i = $upperLimit - 1; $i >= 0; --$i) {
  47313. if (isset($toFind[$diff[$i][1]])) {
  47314. unset($toFind[$diff[$i][1]]);
  47315. $lc = substr($diff[$i][0], -1);
  47316. if ("\n" !== $lc) {
  47317. array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  47318. }
  47319. if (!count($toFind)) {
  47320. break;
  47321. }
  47322. }
  47323. }
  47324. }
  47325. $cutOff = max($this->commonLineThreshold, $this->contextLines);
  47326. $hunkCapture = false;
  47327. $sameCount = $toRange = $fromRange = 0;
  47328. $toStart = $fromStart = 1;
  47329. $i = 0;
  47330. foreach ($diff as $i => $entry) {
  47331. if (0 === $entry[1]) {
  47332. if (false === $hunkCapture) {
  47333. ++$fromStart;
  47334. ++$toStart;
  47335. continue;
  47336. }
  47337. ++$sameCount;
  47338. ++$toRange;
  47339. ++$fromRange;
  47340. if ($sameCount === $cutOff) {
  47341. $contextStartOffset = ($hunkCapture - $this->contextLines) < 0
  47342. ? $hunkCapture
  47343. : $this->contextLines;
  47344. $this->writeHunk(
  47345. $diff,
  47346. $hunkCapture - $contextStartOffset,
  47347. $i - $cutOff + $this->contextLines + 1,
  47348. $fromStart - $contextStartOffset,
  47349. $fromRange - $cutOff + $contextStartOffset + $this->contextLines,
  47350. $toStart - $contextStartOffset,
  47351. $toRange - $cutOff + $contextStartOffset + $this->contextLines,
  47352. $output
  47353. );
  47354. $fromStart += $fromRange;
  47355. $toStart += $toRange;
  47356. $hunkCapture = false;
  47357. $sameCount = $toRange = $fromRange = 0;
  47358. }
  47359. continue;
  47360. }
  47361. $sameCount = 0;
  47362. if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
  47363. continue;
  47364. }
  47365. if (false === $hunkCapture) {
  47366. $hunkCapture = $i;
  47367. }
  47368. if (Differ::ADDED === $entry[1]) {
  47369. ++$toRange;
  47370. }
  47371. if (Differ::REMOVED === $entry[1]) {
  47372. ++$fromRange;
  47373. }
  47374. }
  47375. if (false === $hunkCapture) {
  47376. return;
  47377. }
  47378. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  47379. ? $hunkCapture
  47380. : $this->contextLines;
  47381. $contextEndOffset = min($sameCount, $this->contextLines);
  47382. $fromRange -= $sameCount;
  47383. $toRange -= $sameCount;
  47384. $this->writeHunk(
  47385. $diff,
  47386. $hunkCapture - $contextStartOffset,
  47387. $i - $sameCount + $contextEndOffset + 1,
  47388. $fromStart - $contextStartOffset,
  47389. $fromRange + $contextStartOffset + $contextEndOffset,
  47390. $toStart - $contextStartOffset,
  47391. $toRange + $contextStartOffset + $contextEndOffset,
  47392. $output
  47393. );
  47394. }
  47395. private function writeHunk(
  47396. array $diff,
  47397. int $diffStartIndex,
  47398. int $diffEndIndex,
  47399. int $fromStart,
  47400. int $fromRange,
  47401. int $toStart,
  47402. int $toRange,
  47403. $output
  47404. ): void {
  47405. if ($this->addLineNumbers) {
  47406. fwrite($output, '@@ -' . $fromStart);
  47407. if (!$this->collapseRanges || 1 !== $fromRange) {
  47408. fwrite($output, ',' . $fromRange);
  47409. }
  47410. fwrite($output, ' +' . $toStart);
  47411. if (!$this->collapseRanges || 1 !== $toRange) {
  47412. fwrite($output, ',' . $toRange);
  47413. }
  47414. fwrite($output, " @@\n");
  47415. } else {
  47416. fwrite($output, "@@ @@\n");
  47417. }
  47418. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  47419. if ($diff[$i][1] === Differ::ADDED) {
  47420. fwrite($output, '+' . $diff[$i][0]);
  47421. } elseif ($diff[$i][1] === Differ::REMOVED) {
  47422. fwrite($output, '-' . $diff[$i][0]);
  47423. } elseif ($diff[$i][1] === Differ::OLD) {
  47424. fwrite($output, ' ' . $diff[$i][0]);
  47425. } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
  47426. fwrite($output, "\n");
  47427. } else {
  47428. fwrite($output, ' ' . $diff[$i][0]);
  47429. }
  47430. }
  47431. }
  47432. }
  47433. <?php declare(strict_types=1);
  47434. namespace SebastianBergmann\Diff\Output;
  47435. use function array_merge;
  47436. use function array_splice;
  47437. use function count;
  47438. use function fclose;
  47439. use function fopen;
  47440. use function fwrite;
  47441. use function is_bool;
  47442. use function is_int;
  47443. use function is_string;
  47444. use function max;
  47445. use function min;
  47446. use function sprintf;
  47447. use function stream_get_contents;
  47448. use function substr;
  47449. use SebastianBergmann\Diff\ConfigurationException;
  47450. use SebastianBergmann\Diff\Differ;
  47451. final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
  47452. {
  47453. private static $default = [
  47454. 'collapseRanges' => true,
  47455. 'commonLineThreshold' => 6,
  47456. 'contextLines' => 3,
  47457. 'fromFile' => null,
  47458. 'fromFileDate' => null,
  47459. 'toFile' => null,
  47460. 'toFileDate' => null,
  47461. ];
  47462. private $changed;
  47463. private $collapseRanges;
  47464. private $commonLineThreshold;
  47465. private $header;
  47466. private $contextLines;
  47467. public function __construct(array $options = [])
  47468. {
  47469. $options = array_merge(self::$default, $options);
  47470. if (!is_bool($options['collapseRanges'])) {
  47471. throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']);
  47472. }
  47473. if (!is_int($options['contextLines']) || $options['contextLines'] < 0) {
  47474. throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']);
  47475. }
  47476. if (!is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) {
  47477. throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']);
  47478. }
  47479. $this->assertString($options, 'fromFile');
  47480. $this->assertString($options, 'toFile');
  47481. $this->assertStringOrNull($options, 'fromFileDate');
  47482. $this->assertStringOrNull($options, 'toFileDate');
  47483. $this->header = sprintf(
  47484. "--- %s%s\n+++ %s%s\n",
  47485. $options['fromFile'],
  47486. null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'],
  47487. $options['toFile'],
  47488. null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']
  47489. );
  47490. $this->collapseRanges = $options['collapseRanges'];
  47491. $this->commonLineThreshold = $options['commonLineThreshold'];
  47492. $this->contextLines = $options['contextLines'];
  47493. }
  47494. public function getDiff(array $diff): string
  47495. {
  47496. if (0 === count($diff)) {
  47497. return '';
  47498. }
  47499. $this->changed = false;
  47500. $buffer = fopen('php://memory', 'r+b');
  47501. fwrite($buffer, $this->header);
  47502. $this->writeDiffHunks($buffer, $diff);
  47503. if (!$this->changed) {
  47504. fclose($buffer);
  47505. return '';
  47506. }
  47507. $diff = stream_get_contents($buffer, -1, 0);
  47508. fclose($buffer);
  47509. $last = substr($diff, -1);
  47510. return "\n" !== $last && "\r" !== $last
  47511. ? $diff . "\n"
  47512. : $diff;
  47513. }
  47514. private function writeDiffHunks($output, array $diff): void
  47515. {
  47516. $upperLimit = count($diff);
  47517. if (0 === $diff[$upperLimit - 1][1]) {
  47518. $lc = substr($diff[$upperLimit - 1][0], -1);
  47519. if ("\n" !== $lc) {
  47520. array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  47521. }
  47522. } else {
  47523. $toFind = [1 => true, 2 => true];
  47524. for ($i = $upperLimit - 1; $i >= 0; --$i) {
  47525. if (isset($toFind[$diff[$i][1]])) {
  47526. unset($toFind[$diff[$i][1]]);
  47527. $lc = substr($diff[$i][0], -1);
  47528. if ("\n" !== $lc) {
  47529. array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]);
  47530. }
  47531. if (!count($toFind)) {
  47532. break;
  47533. }
  47534. }
  47535. }
  47536. }
  47537. $cutOff = max($this->commonLineThreshold, $this->contextLines);
  47538. $hunkCapture = false;
  47539. $sameCount = $toRange = $fromRange = 0;
  47540. $toStart = $fromStart = 1;
  47541. $i = 0;
  47542. foreach ($diff as $i => $entry) {
  47543. if (0 === $entry[1]) {
  47544. if (false === $hunkCapture) {
  47545. ++$fromStart;
  47546. ++$toStart;
  47547. continue;
  47548. }
  47549. ++$sameCount;
  47550. ++$toRange;
  47551. ++$fromRange;
  47552. if ($sameCount === $cutOff) {
  47553. $contextStartOffset = ($hunkCapture - $this->contextLines) < 0
  47554. ? $hunkCapture
  47555. : $this->contextLines;
  47556. $this->writeHunk(
  47557. $diff,
  47558. $hunkCapture - $contextStartOffset,
  47559. $i - $cutOff + $this->contextLines + 1,
  47560. $fromStart - $contextStartOffset,
  47561. $fromRange - $cutOff + $contextStartOffset + $this->contextLines,
  47562. $toStart - $contextStartOffset,
  47563. $toRange - $cutOff + $contextStartOffset + $this->contextLines,
  47564. $output
  47565. );
  47566. $fromStart += $fromRange;
  47567. $toStart += $toRange;
  47568. $hunkCapture = false;
  47569. $sameCount = $toRange = $fromRange = 0;
  47570. }
  47571. continue;
  47572. }
  47573. $sameCount = 0;
  47574. if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) {
  47575. continue;
  47576. }
  47577. $this->changed = true;
  47578. if (false === $hunkCapture) {
  47579. $hunkCapture = $i;
  47580. }
  47581. if (Differ::ADDED === $entry[1]) {
  47582. ++$toRange;
  47583. }
  47584. if (Differ::REMOVED === $entry[1]) {
  47585. ++$fromRange;
  47586. }
  47587. }
  47588. if (false === $hunkCapture) {
  47589. return;
  47590. }
  47591. $contextStartOffset = $hunkCapture - $this->contextLines < 0
  47592. ? $hunkCapture
  47593. : $this->contextLines;
  47594. $contextEndOffset = min($sameCount, $this->contextLines);
  47595. $fromRange -= $sameCount;
  47596. $toRange -= $sameCount;
  47597. $this->writeHunk(
  47598. $diff,
  47599. $hunkCapture - $contextStartOffset,
  47600. $i - $sameCount + $contextEndOffset + 1,
  47601. $fromStart - $contextStartOffset,
  47602. $fromRange + $contextStartOffset + $contextEndOffset,
  47603. $toStart - $contextStartOffset,
  47604. $toRange + $contextStartOffset + $contextEndOffset,
  47605. $output
  47606. );
  47607. }
  47608. private function writeHunk(
  47609. array $diff,
  47610. int $diffStartIndex,
  47611. int $diffEndIndex,
  47612. int $fromStart,
  47613. int $fromRange,
  47614. int $toStart,
  47615. int $toRange,
  47616. $output
  47617. ): void {
  47618. fwrite($output, '@@ -' . $fromStart);
  47619. if (!$this->collapseRanges || 1 !== $fromRange) {
  47620. fwrite($output, ',' . $fromRange);
  47621. }
  47622. fwrite($output, ' +' . $toStart);
  47623. if (!$this->collapseRanges || 1 !== $toRange) {
  47624. fwrite($output, ',' . $toRange);
  47625. }
  47626. fwrite($output, " @@\n");
  47627. for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) {
  47628. if ($diff[$i][1] === Differ::ADDED) {
  47629. $this->changed = true;
  47630. fwrite($output, '+' . $diff[$i][0]);
  47631. } elseif ($diff[$i][1] === Differ::REMOVED) {
  47632. $this->changed = true;
  47633. fwrite($output, '-' . $diff[$i][0]);
  47634. } elseif ($diff[$i][1] === Differ::OLD) {
  47635. fwrite($output, ' ' . $diff[$i][0]);
  47636. } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) {
  47637. $this->changed = true;
  47638. fwrite($output, $diff[$i][0]);
  47639. }
  47640. }
  47641. }
  47642. private function assertString(array $options, string $option): void
  47643. {
  47644. if (!is_string($options[$option])) {
  47645. throw new ConfigurationException($option, 'a string', $options[$option]);
  47646. }
  47647. }
  47648. private function assertStringOrNull(array $options, string $option): void
  47649. {
  47650. if (null !== $options[$option] && !is_string($options[$option])) {
  47651. throw new ConfigurationException($option, 'a string or <null>', $options[$option]);
  47652. }
  47653. }
  47654. }
  47655. <?php declare(strict_types=1);
  47656. namespace SebastianBergmann\Diff\Output;
  47657. use function count;
  47658. abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface
  47659. {
  47660. protected function getCommonChunks(array $diff, int $lineThreshold = 5): array
  47661. {
  47662. $diffSize = count($diff);
  47663. $capturing = false;
  47664. $chunkStart = 0;
  47665. $chunkSize = 0;
  47666. $commonChunks = [];
  47667. for ($i = 0; $i < $diffSize; ++$i) {
  47668. if ($diff[$i][1] === 0 ) {
  47669. if ($capturing === false) {
  47670. $capturing = true;
  47671. $chunkStart = $i;
  47672. $chunkSize = 0;
  47673. } else {
  47674. ++$chunkSize;
  47675. }
  47676. } elseif ($capturing !== false) {
  47677. if ($chunkSize >= $lineThreshold) {
  47678. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  47679. }
  47680. $capturing = false;
  47681. }
  47682. }
  47683. if ($capturing !== false && $chunkSize >= $lineThreshold) {
  47684. $commonChunks[$chunkStart] = $chunkStart + $chunkSize;
  47685. }
  47686. return $commonChunks;
  47687. }
  47688. }
  47689. <?php declare(strict_types=1);
  47690. namespace SebastianBergmann\Diff;
  47691. interface LongestCommonSubsequenceCalculator
  47692. {
  47693. public function calculate(array $from, array $to): array;
  47694. }
  47695. <?php declare(strict_types=1);
  47696. namespace SebastianBergmann\Diff;
  47697. final class Chunk
  47698. {
  47699. private $start;
  47700. private $startRange;
  47701. private $end;
  47702. private $endRange;
  47703. private $lines;
  47704. public function __construct(int $start = 0, int $startRange = 1, int $end = 0, int $endRange = 1, array $lines = [])
  47705. {
  47706. $this->start = $start;
  47707. $this->startRange = $startRange;
  47708. $this->end = $end;
  47709. $this->endRange = $endRange;
  47710. $this->lines = $lines;
  47711. }
  47712. public function getStart(): int
  47713. {
  47714. return $this->start;
  47715. }
  47716. public function getStartRange(): int
  47717. {
  47718. return $this->startRange;
  47719. }
  47720. public function getEnd(): int
  47721. {
  47722. return $this->end;
  47723. }
  47724. public function getEndRange(): int
  47725. {
  47726. return $this->endRange;
  47727. }
  47728. public function getLines(): array
  47729. {
  47730. return $this->lines;
  47731. }
  47732. public function setLines(array $lines): void
  47733. {
  47734. foreach ($lines as $line) {
  47735. if (!$line instanceof Line) {
  47736. throw new InvalidArgumentException;
  47737. }
  47738. }
  47739. $this->lines = $lines;
  47740. }
  47741. }
  47742. <?php declare(strict_types=1);
  47743. namespace SebastianBergmann\Diff;
  47744. use const PHP_INT_SIZE;
  47745. use const PREG_SPLIT_DELIM_CAPTURE;
  47746. use const PREG_SPLIT_NO_EMPTY;
  47747. use function array_shift;
  47748. use function array_unshift;
  47749. use function array_values;
  47750. use function count;
  47751. use function current;
  47752. use function end;
  47753. use function get_class;
  47754. use function gettype;
  47755. use function is_array;
  47756. use function is_object;
  47757. use function is_string;
  47758. use function key;
  47759. use function min;
  47760. use function preg_split;
  47761. use function prev;
  47762. use function reset;
  47763. use function sprintf;
  47764. use function substr;
  47765. use SebastianBergmann\Diff\Output\DiffOutputBuilderInterface;
  47766. use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
  47767. final class Differ
  47768. {
  47769. public const OLD = 0;
  47770. public const ADDED = 1;
  47771. public const REMOVED = 2;
  47772. public const DIFF_LINE_END_WARNING = 3;
  47773. public const NO_LINE_END_EOF_WARNING = 4;
  47774. private $outputBuilder;
  47775. public function __construct($outputBuilder = null)
  47776. {
  47777. if ($outputBuilder instanceof DiffOutputBuilderInterface) {
  47778. $this->outputBuilder = $outputBuilder;
  47779. } elseif (null === $outputBuilder) {
  47780. $this->outputBuilder = new UnifiedDiffOutputBuilder;
  47781. } elseif (is_string($outputBuilder)) {
  47782. $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder);
  47783. } else {
  47784. throw new InvalidArgumentException(
  47785. sprintf(
  47786. 'Expected builder to be an instance of DiffOutputBuilderInterface, <null> or a string, got %s.',
  47787. is_object($outputBuilder) ? 'instance of "' . get_class($outputBuilder) . '"' : gettype($outputBuilder) . ' "' . $outputBuilder . '"'
  47788. )
  47789. );
  47790. }
  47791. }
  47792. public function diff($from, $to, ?LongestCommonSubsequenceCalculator $lcs = null): string
  47793. {
  47794. $diff = $this->diffToArray(
  47795. $this->normalizeDiffInput($from),
  47796. $this->normalizeDiffInput($to),
  47797. $lcs
  47798. );
  47799. return $this->outputBuilder->getDiff($diff);
  47800. }
  47801. public function diffToArray($from, $to, ?LongestCommonSubsequenceCalculator $lcs = null): array
  47802. {
  47803. if (is_string($from)) {
  47804. $from = $this->splitStringByLines($from);
  47805. } elseif (!is_array($from)) {
  47806. throw new InvalidArgumentException('"from" must be an array or string.');
  47807. }
  47808. if (is_string($to)) {
  47809. $to = $this->splitStringByLines($to);
  47810. } elseif (!is_array($to)) {
  47811. throw new InvalidArgumentException('"to" must be an array or string.');
  47812. }
  47813. [$from, $to, $start, $end] = self::getArrayDiffParted($from, $to);
  47814. if ($lcs === null) {
  47815. $lcs = $this->selectLcsImplementation($from, $to);
  47816. }
  47817. $common = $lcs->calculate(array_values($from), array_values($to));
  47818. $diff = [];
  47819. foreach ($start as $token) {
  47820. $diff[] = [$token, self::OLD];
  47821. }
  47822. reset($from);
  47823. reset($to);
  47824. foreach ($common as $token) {
  47825. while (($fromToken = reset($from)) !== $token) {
  47826. $diff[] = [array_shift($from), self::REMOVED];
  47827. }
  47828. while (($toToken = reset($to)) !== $token) {
  47829. $diff[] = [array_shift($to), self::ADDED];
  47830. }
  47831. $diff[] = [$token, self::OLD];
  47832. array_shift($from);
  47833. array_shift($to);
  47834. }
  47835. while (($token = array_shift($from)) !== null) {
  47836. $diff[] = [$token, self::REMOVED];
  47837. }
  47838. while (($token = array_shift($to)) !== null) {
  47839. $diff[] = [$token, self::ADDED];
  47840. }
  47841. foreach ($end as $token) {
  47842. $diff[] = [$token, self::OLD];
  47843. }
  47844. if ($this->detectUnmatchedLineEndings($diff)) {
  47845. array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]);
  47846. }
  47847. return $diff;
  47848. }
  47849. private function normalizeDiffInput($input)
  47850. {
  47851. if (!is_array($input) && !is_string($input)) {
  47852. return (string) $input;
  47853. }
  47854. return $input;
  47855. }
  47856. private function splitStringByLines(string $input): array
  47857. {
  47858. return preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  47859. }
  47860. private function selectLcsImplementation(array $from, array $to): LongestCommonSubsequenceCalculator
  47861. {
  47862. $memoryLimit = 100 * 1024 * 1024;
  47863. if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
  47864. return new MemoryEfficientLongestCommonSubsequenceCalculator;
  47865. }
  47866. return new TimeEfficientLongestCommonSubsequenceCalculator;
  47867. }
  47868. private function calculateEstimatedFootprint(array $from, array $to)
  47869. {
  47870. $itemSize = PHP_INT_SIZE === 4 ? 76 : 144;
  47871. return $itemSize * min(count($from), count($to)) ** 2;
  47872. }
  47873. private function detectUnmatchedLineEndings(array $diff): bool
  47874. {
  47875. $newLineBreaks = ['' => true];
  47876. $oldLineBreaks = ['' => true];
  47877. foreach ($diff as $entry) {
  47878. if (self::OLD === $entry[1]) {
  47879. $ln = $this->getLinebreak($entry[0]);
  47880. $oldLineBreaks[$ln] = true;
  47881. $newLineBreaks[$ln] = true;
  47882. } elseif (self::ADDED === $entry[1]) {
  47883. $newLineBreaks[$this->getLinebreak($entry[0])] = true;
  47884. } elseif (self::REMOVED === $entry[1]) {
  47885. $oldLineBreaks[$this->getLinebreak($entry[0])] = true;
  47886. }
  47887. }
  47888. if (['' => true] === $newLineBreaks || ['' => true] === $oldLineBreaks) {
  47889. return false;
  47890. }
  47891. foreach ($newLineBreaks as $break => $set) {
  47892. if (!isset($oldLineBreaks[$break])) {
  47893. return true;
  47894. }
  47895. }
  47896. foreach ($oldLineBreaks as $break => $set) {
  47897. if (!isset($newLineBreaks[$break])) {
  47898. return true;
  47899. }
  47900. }
  47901. return false;
  47902. }
  47903. private function getLinebreak($line): string
  47904. {
  47905. if (!is_string($line)) {
  47906. return '';
  47907. }
  47908. $lc = substr($line, -1);
  47909. if ("\r" === $lc) {
  47910. return "\r";
  47911. }
  47912. if ("\n" !== $lc) {
  47913. return '';
  47914. }
  47915. if ("\r\n" === substr($line, -2)) {
  47916. return "\r\n";
  47917. }
  47918. return "\n";
  47919. }
  47920. private static function getArrayDiffParted(array &$from, array &$to): array
  47921. {
  47922. $start = [];
  47923. $end = [];
  47924. reset($to);
  47925. foreach ($from as $k => $v) {
  47926. $toK = key($to);
  47927. if ($toK === $k && $v === $to[$k]) {
  47928. $start[$k] = $v;
  47929. unset($from[$k], $to[$k]);
  47930. } else {
  47931. break;
  47932. }
  47933. }
  47934. end($from);
  47935. end($to);
  47936. do {
  47937. $fromK = key($from);
  47938. $toK = key($to);
  47939. if (null === $fromK || null === $toK || current($from) !== current($to)) {
  47940. break;
  47941. }
  47942. prev($from);
  47943. prev($to);
  47944. $end = [$fromK => $from[$fromK]] + $end;
  47945. unset($from[$fromK], $to[$toK]);
  47946. } while (true);
  47947. return [$from, $to, $start, $end];
  47948. }
  47949. }
  47950. <?php declare(strict_types=1);
  47951. namespace SebastianBergmann\Diff;
  47952. final class Line
  47953. {
  47954. public const ADDED = 1;
  47955. public const REMOVED = 2;
  47956. public const UNCHANGED = 3;
  47957. private $type;
  47958. private $content;
  47959. public function __construct(int $type = self::UNCHANGED, string $content = '')
  47960. {
  47961. $this->type = $type;
  47962. $this->content = $content;
  47963. }
  47964. public function getContent(): string
  47965. {
  47966. return $this->content;
  47967. }
  47968. public function getType(): int
  47969. {
  47970. return $this->type;
  47971. }
  47972. }
  47973. <?php declare(strict_types=1);
  47974. namespace SebastianBergmann\Diff;
  47975. use function get_class;
  47976. use function gettype;
  47977. use function is_object;
  47978. use function sprintf;
  47979. use Exception;
  47980. final class ConfigurationException extends InvalidArgumentException
  47981. {
  47982. public function __construct(
  47983. string $option,
  47984. string $expected,
  47985. $value,
  47986. int $code = 0,
  47987. ?Exception $previous = null
  47988. ) {
  47989. parent::__construct(
  47990. sprintf(
  47991. 'Option "%s" must be %s, got "%s".',
  47992. $option,
  47993. $expected,
  47994. is_object($value) ? get_class($value) : (null === $value ? '<null>' : gettype($value) . '#' . $value)
  47995. ),
  47996. $code,
  47997. $previous
  47998. );
  47999. }
  48000. }
  48001. <?php declare(strict_types=1);
  48002. namespace SebastianBergmann\Diff;
  48003. class InvalidArgumentException extends \InvalidArgumentException implements Exception
  48004. {
  48005. }
  48006. <?php declare(strict_types=1);
  48007. namespace SebastianBergmann\Diff;
  48008. use Throwable;
  48009. interface Exception extends Throwable
  48010. {
  48011. }
  48012. <?php declare(strict_types=1);
  48013. namespace SebastianBergmann\Diff;
  48014. use function array_fill;
  48015. use function array_merge;
  48016. use function array_reverse;
  48017. use function array_slice;
  48018. use function count;
  48019. use function in_array;
  48020. use function max;
  48021. final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator
  48022. {
  48023. public function calculate(array $from, array $to): array
  48024. {
  48025. $cFrom = count($from);
  48026. $cTo = count($to);
  48027. if ($cFrom === 0) {
  48028. return [];
  48029. }
  48030. if ($cFrom === 1) {
  48031. if (in_array($from[0], $to, true)) {
  48032. return [$from[0]];
  48033. }
  48034. return [];
  48035. }
  48036. $i = (int) ($cFrom / 2);
  48037. $fromStart = array_slice($from, 0, $i);
  48038. $fromEnd = array_slice($from, $i);
  48039. $llB = $this->length($fromStart, $to);
  48040. $llE = $this->length(array_reverse($fromEnd), array_reverse($to));
  48041. $jMax = 0;
  48042. $max = 0;
  48043. for ($j = 0; $j <= $cTo; $j++) {
  48044. $m = $llB[$j] + $llE[$cTo - $j];
  48045. if ($m >= $max) {
  48046. $max = $m;
  48047. $jMax = $j;
  48048. }
  48049. }
  48050. $toStart = array_slice($to, 0, $jMax);
  48051. $toEnd = array_slice($to, $jMax);
  48052. return array_merge(
  48053. $this->calculate($fromStart, $toStart),
  48054. $this->calculate($fromEnd, $toEnd)
  48055. );
  48056. }
  48057. private function length(array $from, array $to): array
  48058. {
  48059. $current = array_fill(0, count($to) + 1, 0);
  48060. $cFrom = count($from);
  48061. $cTo = count($to);
  48062. for ($i = 0; $i < $cFrom; $i++) {
  48063. $prev = $current;
  48064. for ($j = 0; $j < $cTo; $j++) {
  48065. if ($from[$i] === $to[$j]) {
  48066. $current[$j + 1] = $prev[$j] + 1;
  48067. } else {
  48068. if ($current[$j] > $prev[$j + 1]) {
  48069. $current[$j + 1] = $current[$j];
  48070. } else {
  48071. $current[$j + 1] = $prev[$j + 1];
  48072. }
  48073. }
  48074. }
  48075. }
  48076. return $current;
  48077. }
  48078. }
  48079. <?php
  48080. declare(strict_types=1);
  48081. namespace PhpCsFixer;
  48082. use Symfony\Component\Finder\Finder as BaseFinder;
  48083. class Finder extends BaseFinder
  48084. {
  48085. public function __construct()
  48086. {
  48087. parent::__construct();
  48088. $this
  48089. ->files()
  48090. ->name('/\.php$/')
  48091. ->exclude('vendor')
  48092. ;
  48093. }
  48094. }
  48095. <?php
  48096. declare(strict_types=1);
  48097. namespace PhpCsFixer\Fixer\ClassNotation;
  48098. use PhpCsFixer\AbstractFixer;
  48099. use PhpCsFixer\FixerDefinition\CodeSample;
  48100. use PhpCsFixer\FixerDefinition\FixerDefinition;
  48101. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  48102. use PhpCsFixer\Tokenizer\CT;
  48103. use PhpCsFixer\Tokenizer\FCT;
  48104. use PhpCsFixer\Tokenizer\Token;
  48105. use PhpCsFixer\Tokenizer\Tokens;
  48106. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  48107. final class ProtectedToPrivateFixer extends AbstractFixer
  48108. {
  48109. private const MODIFIER_KINDS = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_NS_SEPARATOR, T_STRING, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, T_STATIC, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET];
  48110. private TokensAnalyzer $tokensAnalyzer;
  48111. public function getDefinition(): FixerDefinitionInterface
  48112. {
  48113. return new FixerDefinition(
  48114. 'Converts `protected` variables and methods to `private` where possible.',
  48115. [
  48116. new CodeSample(
  48117. '<?php
  48118. final class Sample
  48119. {
  48120. protected $a;
  48121. protected function test()
  48122. {
  48123. }
  48124. }
  48125. '
  48126. ),
  48127. ]
  48128. );
  48129. }
  48130. public function getPriority(): int
  48131. {
  48132. return 66;
  48133. }
  48134. public function isCandidate(Tokens $tokens): bool
  48135. {
  48136. return $tokens->isAnyTokenKindsFound([T_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, FCT::T_PROTECTED_SET])
  48137. && (
  48138. $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL])
  48139. || $tokens->isTokenKindFound(FCT::T_ENUM)
  48140. );
  48141. }
  48142. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  48143. {
  48144. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  48145. $classesCandidate = [];
  48146. $classElementTypes = ['method' => true, 'property' => true, 'promoted_property' => true, 'const' => true];
  48147. foreach ($this->tokensAnalyzer->getClassyElements() as $index => $element) {
  48148. $classIndex = $element['classIndex'];
  48149. $classesCandidate[$classIndex] ??= $this->isClassCandidate($tokens, $classIndex);
  48150. if (false === $classesCandidate[$classIndex]) {
  48151. continue;
  48152. }
  48153. if (!isset($classElementTypes[$element['type']])) {
  48154. continue;
  48155. }
  48156. $previousIndex = $index;
  48157. $protectedIndex = null;
  48158. $protectedPromotedIndex = null;
  48159. $protectedSetIndex = null;
  48160. $isFinal = false;
  48161. do {
  48162. $previousIndex = $tokens->getPrevMeaningfulToken($previousIndex);
  48163. if ($tokens[$previousIndex]->isGivenKind(T_PROTECTED)) {
  48164. $protectedIndex = $previousIndex;
  48165. } elseif ($tokens[$previousIndex]->isGivenKind(CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED)) {
  48166. $protectedPromotedIndex = $previousIndex;
  48167. } elseif ($tokens[$previousIndex]->isGivenKind(FCT::T_PROTECTED_SET)) {
  48168. $protectedSetIndex = $previousIndex;
  48169. } elseif ($tokens[$previousIndex]->isGivenKind(T_FINAL)) {
  48170. $isFinal = true;
  48171. }
  48172. } while ($tokens[$previousIndex]->isGivenKind(self::MODIFIER_KINDS));
  48173. if ($isFinal && 'const' === $element['type']) {
  48174. continue;
  48175. }
  48176. if (null !== $protectedIndex) {
  48177. $tokens[$protectedIndex] = new Token([T_PRIVATE, 'private']);
  48178. }
  48179. if (null !== $protectedPromotedIndex) {
  48180. $tokens[$protectedPromotedIndex] = new Token([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, 'private']);
  48181. }
  48182. if (null !== $protectedSetIndex) {
  48183. $tokens[$protectedSetIndex] = new Token([T_PRIVATE_SET, 'private(set)']);
  48184. }
  48185. }
  48186. }
  48187. private function isClassCandidate(Tokens $tokens, int $classIndex): bool
  48188. {
  48189. if ($tokens[$classIndex]->isGivenKind(FCT::T_ENUM)) {
  48190. return true;
  48191. }
  48192. if (!$tokens[$classIndex]->isGivenKind(T_CLASS) || $this->tokensAnalyzer->isAnonymousClass($classIndex)) {
  48193. return false;
  48194. }
  48195. $modifiers = $this->tokensAnalyzer->getClassyModifiers($classIndex);
  48196. if (!isset($modifiers['final'])) {
  48197. return false;
  48198. }
  48199. $classNameIndex = $tokens->getNextMeaningfulToken($classIndex);
  48200. $classExtendsIndex = $tokens->getNextMeaningfulToken($classNameIndex);
  48201. if ($tokens[$classExtendsIndex]->isGivenKind(T_EXTENDS)) {
  48202. return false;
  48203. }
  48204. if (!$tokens->isTokenKindFound(CT::T_USE_TRAIT)) {
  48205. return true;
  48206. }
  48207. $classOpenIndex = $tokens->getNextTokenOfKind($classNameIndex, ['{']);
  48208. $classCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpenIndex);
  48209. $useIndex = $tokens->getNextTokenOfKind($classOpenIndex, [[CT::T_USE_TRAIT]]);
  48210. return null === $useIndex || $useIndex > $classCloseIndex;
  48211. }
  48212. }
  48213. <?php
  48214. declare(strict_types=1);
  48215. namespace PhpCsFixer\Fixer\ClassNotation;
  48216. use PhpCsFixer\AbstractFixer;
  48217. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  48218. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  48219. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  48220. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  48221. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  48222. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  48223. use PhpCsFixer\FixerDefinition\CodeSample;
  48224. use PhpCsFixer\FixerDefinition\FixerDefinition;
  48225. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  48226. use PhpCsFixer\Tokenizer\CT;
  48227. use PhpCsFixer\Tokenizer\FCT;
  48228. use PhpCsFixer\Tokenizer\Token;
  48229. use PhpCsFixer\Tokenizer\Tokens;
  48230. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  48231. /**
  48232. @phpstan-type
  48233. @phpstan-type
  48234. @phpstan-type
  48235. @phpstan-type
  48236. @phpstan-type
  48237. @implements
  48238. */
  48239. final class ClassDefinitionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  48240. {
  48241. /**
  48242. @use */
  48243. use ConfigurableFixerTrait;
  48244. public function getDefinition(): FixerDefinitionInterface
  48245. {
  48246. return new FixerDefinition(
  48247. 'Whitespace around the keywords of a class, trait, enum or interfaces definition should be one space.',
  48248. [
  48249. new CodeSample(
  48250. '<?php
  48251. class Foo extends Bar implements Baz, BarBaz
  48252. {
  48253. }
  48254. final class Foo extends Bar implements Baz, BarBaz
  48255. {
  48256. }
  48257. trait Foo
  48258. {
  48259. }
  48260. $foo = new class extends Bar implements Baz, BarBaz {};
  48261. '
  48262. ),
  48263. new CodeSample(
  48264. '<?php
  48265. class Foo
  48266. extends Bar
  48267. implements Baz, BarBaz
  48268. {}
  48269. ',
  48270. ['single_line' => true]
  48271. ),
  48272. new CodeSample(
  48273. '<?php
  48274. class Foo
  48275. extends Bar
  48276. implements Baz
  48277. {}
  48278. ',
  48279. ['single_item_single_line' => true]
  48280. ),
  48281. new CodeSample(
  48282. '<?php
  48283. interface Bar extends
  48284. Bar, BarBaz, FooBarBaz
  48285. {}
  48286. ',
  48287. ['multi_line_extends_each_single_line' => true]
  48288. ),
  48289. new CodeSample(
  48290. '<?php
  48291. $foo = new class(){};
  48292. ',
  48293. ['space_before_parenthesis' => true]
  48294. ),
  48295. new CodeSample(
  48296. "<?php\n\$foo = new class(\n \$bar,\n \$baz\n) {};\n",
  48297. ['inline_constructor_arguments' => true]
  48298. ),
  48299. ]
  48300. );
  48301. }
  48302. public function getPriority(): int
  48303. {
  48304. return 36;
  48305. }
  48306. public function isCandidate(Tokens $tokens): bool
  48307. {
  48308. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  48309. }
  48310. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  48311. {
  48312. for ($index = $tokens->getSize() - 4; $index > 0; --$index) {
  48313. if ($tokens[$index]->isClassy()) {
  48314. $this->fixClassyDefinition($tokens, $index);
  48315. }
  48316. }
  48317. }
  48318. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  48319. {
  48320. return new FixerConfigurationResolver([
  48321. (new FixerOptionBuilder('multi_line_extends_each_single_line', 'Whether definitions should be multiline.'))
  48322. ->setAllowedTypes(['bool'])
  48323. ->setDefault(false)
  48324. ->getOption(),
  48325. (new FixerOptionBuilder('single_item_single_line', 'Whether definitions should be single line when including a single item.'))
  48326. ->setAllowedTypes(['bool'])
  48327. ->setDefault(false)
  48328. ->getOption(),
  48329. (new FixerOptionBuilder('single_line', 'Whether definitions should be single line.'))
  48330. ->setAllowedTypes(['bool'])
  48331. ->setDefault(false)
  48332. ->getOption(),
  48333. (new FixerOptionBuilder('space_before_parenthesis', 'Whether there should be a single space after the parenthesis of anonymous class (PSR12) or not.'))
  48334. ->setAllowedTypes(['bool'])
  48335. ->setDefault(false)
  48336. ->getOption(),
  48337. (new FixerOptionBuilder('inline_constructor_arguments', 'Whether constructor argument list in anonymous classes should be single line.'))
  48338. ->setAllowedTypes(['bool'])
  48339. ->setDefault(true)
  48340. ->getOption(),
  48341. ]);
  48342. }
  48343. private function fixClassyDefinition(Tokens $tokens, int $classyIndex): void
  48344. {
  48345. $classDefInfo = $this->getClassyDefinitionInfo($tokens, $classyIndex);
  48346. if (false !== $classDefInfo['implements']) {
  48347. $classDefInfo['implements'] = $this->fixClassyDefinitionImplements(
  48348. $tokens,
  48349. $classDefInfo['open'],
  48350. $classDefInfo['implements']
  48351. );
  48352. }
  48353. if (false !== $classDefInfo['extends']) {
  48354. $classDefInfo['extends'] = $this->fixClassyDefinitionExtends(
  48355. $tokens,
  48356. false === $classDefInfo['implements'] ? $classDefInfo['open'] : $classDefInfo['implements']['start'],
  48357. $classDefInfo['extends']
  48358. );
  48359. }
  48360. $classDefInfo['open'] = $this->fixClassyDefinitionOpenSpacing($tokens, $classDefInfo);
  48361. if (false !== $classDefInfo['implements']) {
  48362. $end = $classDefInfo['implements']['start'];
  48363. } elseif (false !== $classDefInfo['extends']) {
  48364. $end = $classDefInfo['extends']['start'];
  48365. } else {
  48366. $end = $tokens->getPrevNonWhitespace($classDefInfo['open']);
  48367. }
  48368. if ($classDefInfo['anonymousClass'] && false === $this->configuration['inline_constructor_arguments']) {
  48369. if (!$tokens[$end]->equals(')')) {
  48370. $start = $tokens->getPrevMeaningfulToken($end);
  48371. $this->makeClassyDefinitionSingleLine($tokens, $start, $end);
  48372. $end = $start;
  48373. }
  48374. if ($tokens[$end]->equals(')')) {
  48375. $end = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $end);
  48376. }
  48377. }
  48378. $this->makeClassyDefinitionSingleLine($tokens, $classDefInfo['start'], $end);
  48379. $this->sortClassModifiers($tokens, $classDefInfo);
  48380. }
  48381. private function fixClassyDefinitionExtends(Tokens $tokens, int $classOpenIndex, array $classExtendsInfo): array
  48382. {
  48383. $endIndex = $tokens->getPrevNonWhitespace($classOpenIndex);
  48384. if (true === $this->configuration['single_line'] || false === $classExtendsInfo['multiLine']) {
  48385. $this->makeClassyDefinitionSingleLine($tokens, $classExtendsInfo['start'], $endIndex);
  48386. $classExtendsInfo['multiLine'] = false;
  48387. } elseif (true === $this->configuration['single_item_single_line'] && 1 === $classExtendsInfo['numberOfExtends']) {
  48388. $this->makeClassyDefinitionSingleLine($tokens, $classExtendsInfo['start'], $endIndex);
  48389. $classExtendsInfo['multiLine'] = false;
  48390. } elseif (true === $this->configuration['multi_line_extends_each_single_line'] && $classExtendsInfo['multiLine']) {
  48391. $this->makeClassyInheritancePartMultiLine($tokens, $classExtendsInfo['start'], $endIndex);
  48392. $classExtendsInfo['multiLine'] = true;
  48393. }
  48394. return $classExtendsInfo;
  48395. }
  48396. private function fixClassyDefinitionImplements(Tokens $tokens, int $classOpenIndex, array $classImplementsInfo): array
  48397. {
  48398. $endIndex = $tokens->getPrevNonWhitespace($classOpenIndex);
  48399. if (true === $this->configuration['single_line'] || false === $classImplementsInfo['multiLine']) {
  48400. $this->makeClassyDefinitionSingleLine($tokens, $classImplementsInfo['start'], $endIndex);
  48401. $classImplementsInfo['multiLine'] = false;
  48402. } elseif (true === $this->configuration['single_item_single_line'] && 1 === $classImplementsInfo['numberOfImplements']) {
  48403. $this->makeClassyDefinitionSingleLine($tokens, $classImplementsInfo['start'], $endIndex);
  48404. $classImplementsInfo['multiLine'] = false;
  48405. } else {
  48406. $this->makeClassyInheritancePartMultiLine($tokens, $classImplementsInfo['start'], $endIndex);
  48407. $classImplementsInfo['multiLine'] = true;
  48408. }
  48409. return $classImplementsInfo;
  48410. }
  48411. private function fixClassyDefinitionOpenSpacing(Tokens $tokens, array $classDefInfo): int
  48412. {
  48413. if ($classDefInfo['anonymousClass']) {
  48414. if (false !== $classDefInfo['implements']) {
  48415. $spacing = $classDefInfo['implements']['multiLine'] ? $this->whitespacesConfig->getLineEnding() : ' ';
  48416. } elseif (false !== $classDefInfo['extends']) {
  48417. $spacing = $classDefInfo['extends']['multiLine'] ? $this->whitespacesConfig->getLineEnding() : ' ';
  48418. } else {
  48419. $spacing = ' ';
  48420. }
  48421. } else {
  48422. $spacing = $this->whitespacesConfig->getLineEnding();
  48423. }
  48424. $openIndex = $tokens->getNextTokenOfKind($classDefInfo['classy'], ['{']);
  48425. if (' ' !== $spacing && str_contains($tokens[$openIndex - 1]->getContent(), "\n")) {
  48426. return $openIndex;
  48427. }
  48428. if ($tokens[$openIndex - 1]->isWhitespace()) {
  48429. if (' ' !== $spacing || !$tokens[$tokens->getPrevNonWhitespace($openIndex - 1)]->isComment()) {
  48430. $tokens[$openIndex - 1] = new Token([T_WHITESPACE, $spacing]);
  48431. }
  48432. return $openIndex;
  48433. }
  48434. $tokens->insertAt($openIndex, new Token([T_WHITESPACE, $spacing]));
  48435. return $openIndex + 1;
  48436. }
  48437. private function getClassyDefinitionInfo(Tokens $tokens, int $classyIndex): array
  48438. {
  48439. $tokensAnalyzer = new TokensAnalyzer($tokens);
  48440. $openIndex = $tokens->getNextTokenOfKind($classyIndex, ['{']);
  48441. $def = [
  48442. 'classy' => $classyIndex,
  48443. 'open' => $openIndex,
  48444. 'extends' => false,
  48445. 'implements' => false,
  48446. 'anonymousClass' => false,
  48447. 'final' => false,
  48448. 'abstract' => false,
  48449. 'readonly' => false,
  48450. ];
  48451. if (!$tokens[$classyIndex]->isGivenKind(T_TRAIT)) {
  48452. $extends = $tokens->findGivenKind(T_EXTENDS, $classyIndex, $openIndex);
  48453. $def['extends'] = [] !== $extends ? $this->getClassyInheritanceInfo($tokens, array_key_first($extends), 'numberOfExtends') : false;
  48454. if (!$tokens[$classyIndex]->isGivenKind(T_INTERFACE)) {
  48455. $implements = $tokens->findGivenKind(T_IMPLEMENTS, $classyIndex, $openIndex);
  48456. $def['implements'] = [] !== $implements ? $this->getClassyInheritanceInfo($tokens, array_key_first($implements), 'numberOfImplements') : false;
  48457. $def['anonymousClass'] = $tokensAnalyzer->isAnonymousClass($classyIndex);
  48458. }
  48459. }
  48460. if ($def['anonymousClass']) {
  48461. $startIndex = $tokens->getPrevTokenOfKind($classyIndex, [[T_NEW]]);
  48462. } else {
  48463. $modifiers = $tokensAnalyzer->getClassyModifiers($classyIndex);
  48464. $startIndex = $classyIndex;
  48465. foreach (['final', 'abstract', 'readonly'] as $modifier) {
  48466. if (isset($modifiers[$modifier])) {
  48467. $def[$modifier] = $modifiers[$modifier];
  48468. $startIndex = min($startIndex, $modifiers[$modifier]);
  48469. } else {
  48470. $def[$modifier] = false;
  48471. }
  48472. }
  48473. }
  48474. $def['start'] = $startIndex;
  48475. return $def;
  48476. }
  48477. private function getClassyInheritanceInfo(Tokens $tokens, int $startIndex, string $label): array
  48478. {
  48479. $implementsInfo = ['start' => $startIndex, $label => 1, 'multiLine' => false];
  48480. ++$startIndex;
  48481. $endIndex = $tokens->getNextTokenOfKind($startIndex, ['{', [T_IMPLEMENTS], [T_EXTENDS]]);
  48482. $endIndex = $tokens[$endIndex]->equals('{') ? $tokens->getPrevNonWhitespace($endIndex) : $endIndex;
  48483. for ($i = $startIndex; $i < $endIndex; ++$i) {
  48484. if ($tokens[$i]->equals(',')) {
  48485. ++$implementsInfo[$label];
  48486. continue;
  48487. }
  48488. if (!$implementsInfo['multiLine'] && str_contains($tokens[$i]->getContent(), "\n")) {
  48489. $implementsInfo['multiLine'] = true;
  48490. }
  48491. }
  48492. return $implementsInfo;
  48493. }
  48494. private function makeClassyDefinitionSingleLine(Tokens $tokens, int $startIndex, int $endIndex): void
  48495. {
  48496. for ($i = $endIndex; $i >= $startIndex; --$i) {
  48497. if ($tokens[$i]->isWhitespace()) {
  48498. if (str_contains($tokens[$i]->getContent(), "\n")) {
  48499. if ($tokens[$i - 1]->isGivenKind(CT::T_ATTRIBUTE_CLOSE) || $tokens[$i + 1]->isGivenKind(FCT::T_ATTRIBUTE)) {
  48500. continue;
  48501. }
  48502. if (($tokens[$i - 1]->isComment() && str_ends_with($tokens[$i - 1]->getContent(), ']'))
  48503. || ($tokens[$i + 1]->isComment() && str_starts_with($tokens[$i + 1]->getContent(), '#['))
  48504. ) {
  48505. continue;
  48506. }
  48507. if ($tokens[$i - 1]->isGivenKind(T_DOC_COMMENT) || $tokens[$i + 1]->isGivenKind(T_DOC_COMMENT)) {
  48508. continue;
  48509. }
  48510. }
  48511. if ($tokens[$i - 1]->isComment()) {
  48512. $content = $tokens[$i - 1]->getContent();
  48513. if (!str_starts_with($content, '//') && !str_starts_with($content, '#')) {
  48514. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  48515. }
  48516. continue;
  48517. }
  48518. if ($tokens[$i + 1]->isComment()) {
  48519. $content = $tokens[$i + 1]->getContent();
  48520. if (!str_starts_with($content, '//')) {
  48521. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  48522. }
  48523. continue;
  48524. }
  48525. if ($tokens[$i - 1]->isGivenKind(T_CLASS) && $tokens[$i + 1]->equals('(')) {
  48526. if (true === $this->configuration['space_before_parenthesis']) {
  48527. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  48528. } else {
  48529. $tokens->clearAt($i);
  48530. }
  48531. continue;
  48532. }
  48533. if (!$tokens[$i - 1]->equals(',') && $tokens[$i + 1]->equalsAny([',', ')']) || $tokens[$i - 1]->equals('(')) {
  48534. $tokens->clearAt($i);
  48535. continue;
  48536. }
  48537. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  48538. continue;
  48539. }
  48540. if ($tokens[$i]->equals(',') && !$tokens[$i + 1]->isWhitespace()) {
  48541. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  48542. continue;
  48543. }
  48544. if (true === $this->configuration['space_before_parenthesis'] && $tokens[$i]->isGivenKind(T_CLASS) && !$tokens[$i + 1]->isWhitespace()) {
  48545. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  48546. continue;
  48547. }
  48548. if (!$tokens[$i]->isComment()) {
  48549. continue;
  48550. }
  48551. if (!$tokens[$i + 1]->isWhitespace() && !$tokens[$i + 1]->isComment() && !str_contains($tokens[$i]->getContent(), "\n")) {
  48552. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  48553. }
  48554. if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i - 1]->isComment()) {
  48555. $tokens->insertAt($i, new Token([T_WHITESPACE, ' ']));
  48556. }
  48557. }
  48558. }
  48559. private function makeClassyInheritancePartMultiLine(Tokens $tokens, int $startIndex, int $endIndex): void
  48560. {
  48561. for ($i = $endIndex; $i > $startIndex; --$i) {
  48562. $previousInterfaceImplementingIndex = $tokens->getPrevTokenOfKind($i, [',', [T_IMPLEMENTS], [T_EXTENDS]]);
  48563. $breakAtIndex = $tokens->getNextMeaningfulToken($previousInterfaceImplementingIndex);
  48564. $this->makeClassyDefinitionSingleLine(
  48565. $tokens,
  48566. $breakAtIndex,
  48567. $i
  48568. );
  48569. $isOnOwnLine = false;
  48570. for ($j = $breakAtIndex; $j > $previousInterfaceImplementingIndex; --$j) {
  48571. if (str_contains($tokens[$j]->getContent(), "\n")) {
  48572. $isOnOwnLine = true;
  48573. break;
  48574. }
  48575. }
  48576. if (!$isOnOwnLine) {
  48577. if ($tokens[$breakAtIndex - 1]->isWhitespace()) {
  48578. $tokens[$breakAtIndex - 1] = new Token([
  48579. T_WHITESPACE,
  48580. $this->whitespacesConfig->getLineEnding().$this->whitespacesConfig->getIndent(),
  48581. ]);
  48582. } else {
  48583. $tokens->insertAt($breakAtIndex, new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding().$this->whitespacesConfig->getIndent()]));
  48584. }
  48585. }
  48586. $i = $previousInterfaceImplementingIndex + 1;
  48587. }
  48588. }
  48589. private function sortClassModifiers(Tokens $tokens, array $classDefInfo): void
  48590. {
  48591. if (false === $classDefInfo['readonly']) {
  48592. return;
  48593. }
  48594. $readonlyIndex = $classDefInfo['readonly'];
  48595. foreach (['final', 'abstract'] as $accessModifier) {
  48596. if (false === $classDefInfo[$accessModifier] || $classDefInfo[$accessModifier] < $readonlyIndex) {
  48597. continue;
  48598. }
  48599. $accessModifierIndex = $classDefInfo[$accessModifier];
  48600. $readonlyToken = clone $tokens[$readonlyIndex];
  48601. $accessToken = clone $tokens[$accessModifierIndex];
  48602. $tokens[$readonlyIndex] = $accessToken;
  48603. $tokens[$accessModifierIndex] = $readonlyToken;
  48604. break;
  48605. }
  48606. }
  48607. }
  48608. <?php
  48609. declare(strict_types=1);
  48610. namespace PhpCsFixer\Fixer\ClassNotation;
  48611. use PhpCsFixer\AbstractFixer;
  48612. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  48613. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  48614. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  48615. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  48616. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  48617. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  48618. use PhpCsFixer\FixerDefinition\CodeSample;
  48619. use PhpCsFixer\FixerDefinition\FixerDefinition;
  48620. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  48621. use PhpCsFixer\Preg;
  48622. use PhpCsFixer\Tokenizer\CT;
  48623. use PhpCsFixer\Tokenizer\FCT;
  48624. use PhpCsFixer\Tokenizer\Token;
  48625. use PhpCsFixer\Tokenizer\Tokens;
  48626. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  48627. /**
  48628. @phpstan-type
  48629. @phpstan-type
  48630. @implements
  48631. */
  48632. final class SingleClassElementPerStatementFixer extends AbstractFixer implements ConfigurableFixerInterface
  48633. {
  48634. /**
  48635. @use */
  48636. use ConfigurableFixerTrait;
  48637. public function isCandidate(Tokens $tokens): bool
  48638. {
  48639. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  48640. }
  48641. public function getPriority(): int
  48642. {
  48643. return 56;
  48644. }
  48645. public function getDefinition(): FixerDefinitionInterface
  48646. {
  48647. return new FixerDefinition(
  48648. 'There MUST NOT be more than one property or constant declared per statement.',
  48649. [
  48650. new CodeSample(
  48651. '<?php
  48652. final class Example
  48653. {
  48654. const FOO_1 = 1, FOO_2 = 2;
  48655. private static $bar1 = array(1,2,3), $bar2 = [1,2,3];
  48656. }
  48657. '
  48658. ),
  48659. new CodeSample(
  48660. '<?php
  48661. final class Example
  48662. {
  48663. const FOO_1 = 1, FOO_2 = 2;
  48664. private static $bar1 = array(1,2,3), $bar2 = [1,2,3];
  48665. }
  48666. ',
  48667. ['elements' => ['property']]
  48668. ),
  48669. ]
  48670. );
  48671. }
  48672. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  48673. {
  48674. $analyzer = new TokensAnalyzer($tokens);
  48675. $elements = array_reverse($analyzer->getClassyElements(), true);
  48676. foreach ($elements as $index => $element) {
  48677. if (!\in_array($element['type'], $this->configuration['elements'], true)) {
  48678. continue;
  48679. }
  48680. $this->fixElement($tokens, $element['type'], $index);
  48681. }
  48682. }
  48683. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  48684. {
  48685. $values = ['const', 'property'];
  48686. return new FixerConfigurationResolver([
  48687. (new FixerOptionBuilder('elements', 'List of strings which element should be modified.'))
  48688. ->setDefault($values)
  48689. ->setAllowedTypes(['string[]'])
  48690. ->setAllowedValues([new AllowedValueSubset($values)])
  48691. ->getOption(),
  48692. ]);
  48693. }
  48694. private function fixElement(Tokens $tokens, string $type, int $index): void
  48695. {
  48696. $tokensAnalyzer = new TokensAnalyzer($tokens);
  48697. $repeatIndex = $index;
  48698. while (true) {
  48699. $repeatIndex = $tokens->getNextMeaningfulToken($repeatIndex);
  48700. $repeatToken = $tokens[$repeatIndex];
  48701. if ($tokensAnalyzer->isArray($repeatIndex)) {
  48702. if ($repeatToken->isGivenKind(T_ARRAY)) {
  48703. $repeatIndex = $tokens->getNextTokenOfKind($repeatIndex, ['(']);
  48704. $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $repeatIndex);
  48705. } else {
  48706. $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $repeatIndex);
  48707. }
  48708. continue;
  48709. }
  48710. if ($repeatToken->equalsAny([';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]])) {
  48711. return;
  48712. }
  48713. if ($repeatToken->equals(',')) {
  48714. break;
  48715. }
  48716. }
  48717. $start = $tokens->getPrevTokenOfKind($index, [';', '{', '}']);
  48718. $this->expandElement(
  48719. $tokens,
  48720. $type,
  48721. $tokens->getNextMeaningfulToken($start),
  48722. $tokens->getNextTokenOfKind($index, [';'])
  48723. );
  48724. }
  48725. private function expandElement(Tokens $tokens, string $type, int $startIndex, int $endIndex): void
  48726. {
  48727. $divisionContent = null;
  48728. if ($tokens[$startIndex - 1]->isWhitespace()) {
  48729. $divisionContent = $tokens[$startIndex - 1]->getContent();
  48730. if (Preg::match('#(\n|\r\n)#', $divisionContent, $matches)) {
  48731. $divisionContent = $matches[0].trim($divisionContent, "\r\n");
  48732. }
  48733. }
  48734. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  48735. $token = $tokens[$i];
  48736. if ($token->equals(')')) {
  48737. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  48738. continue;
  48739. }
  48740. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  48741. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $i);
  48742. continue;
  48743. }
  48744. if (!$tokens[$i]->equals(',')) {
  48745. continue;
  48746. }
  48747. $tokens[$i] = new Token(';');
  48748. if ($tokens[$i + 1]->isWhitespace()) {
  48749. $tokens->clearAt($i + 1);
  48750. }
  48751. if (null !== $divisionContent && '' !== $divisionContent) {
  48752. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, $divisionContent]));
  48753. }
  48754. $sequence = $this->getModifiersSequences($tokens, $type, $startIndex, $endIndex);
  48755. $tokens->insertAt($i + 2, $sequence);
  48756. }
  48757. }
  48758. private function getModifiersSequences(Tokens $tokens, string $type, int $startIndex, int $endIndex): array
  48759. {
  48760. if ('property' === $type) {
  48761. $tokenKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_STATIC, T_VAR, T_STRING, T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  48762. } else {
  48763. $tokenKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_CONST];
  48764. }
  48765. $sequence = [];
  48766. for ($i = $startIndex; $i < $endIndex - 1; ++$i) {
  48767. if ($tokens[$i]->isComment()) {
  48768. continue;
  48769. }
  48770. if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isGivenKind($tokenKinds)) {
  48771. break;
  48772. }
  48773. $sequence[] = clone $tokens[$i];
  48774. }
  48775. return $sequence;
  48776. }
  48777. }
  48778. <?php
  48779. declare(strict_types=1);
  48780. namespace PhpCsFixer\Fixer\ClassNotation;
  48781. use PhpCsFixer\AbstractFixer;
  48782. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  48783. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  48784. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  48785. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  48786. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  48787. use PhpCsFixer\FixerDefinition\CodeSample;
  48788. use PhpCsFixer\FixerDefinition\FixerDefinition;
  48789. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  48790. use PhpCsFixer\Tokenizer\CT;
  48791. use PhpCsFixer\Tokenizer\FCT;
  48792. use PhpCsFixer\Tokenizer\Token;
  48793. use PhpCsFixer\Tokenizer\Tokens;
  48794. use PhpCsFixer\Utils;
  48795. /**
  48796. @phpstan-type
  48797. @phpstan-type
  48798. @phpstan-type
  48799. @implements
  48800. */
  48801. final class OrderedClassElementsFixer extends AbstractFixer implements ConfigurableFixerInterface
  48802. {
  48803. /**
  48804. @use */
  48805. use ConfigurableFixerTrait;
  48806. public const SORT_ALPHA = 'alpha';
  48807. public const SORT_NONE = 'none';
  48808. private const SUPPORTED_SORT_ALGORITHMS = [
  48809. self::SORT_NONE,
  48810. self::SORT_ALPHA,
  48811. ];
  48812. private const TYPE_HIERARCHY = [
  48813. 'use_trait' => null,
  48814. 'public' => null,
  48815. 'protected' => null,
  48816. 'private' => null,
  48817. 'case' => ['public'],
  48818. 'constant' => null,
  48819. 'constant_public' => ['constant', 'public'],
  48820. 'constant_protected' => ['constant', 'protected'],
  48821. 'constant_private' => ['constant', 'private'],
  48822. 'property' => null,
  48823. 'property_static' => ['property'],
  48824. 'property_public' => ['property', 'public'],
  48825. 'property_protected' => ['property', 'protected'],
  48826. 'property_private' => ['property', 'private'],
  48827. 'property_public_abstract' => ['property_abstract', 'property_public'],
  48828. 'property_public_readonly' => ['property_readonly', 'property_public'],
  48829. 'property_protected_abstract' => ['property_abstract', 'property_protected'],
  48830. 'property_protected_readonly' => ['property_readonly', 'property_protected'],
  48831. 'property_private_readonly' => ['property_readonly', 'property_private'],
  48832. 'property_public_static' => ['property_static', 'property_public'],
  48833. 'property_protected_static' => ['property_static', 'property_protected'],
  48834. 'property_private_static' => ['property_static', 'property_private'],
  48835. 'method' => null,
  48836. 'method_abstract' => ['method'],
  48837. 'method_static' => ['method'],
  48838. 'method_public' => ['method', 'public'],
  48839. 'method_protected' => ['method', 'protected'],
  48840. 'method_private' => ['method', 'private'],
  48841. 'method_public_abstract' => ['method_abstract', 'method_public'],
  48842. 'method_protected_abstract' => ['method_abstract', 'method_protected'],
  48843. 'method_private_abstract' => ['method_abstract', 'method_private'],
  48844. 'method_public_abstract_static' => ['method_abstract', 'method_static', 'method_public'],
  48845. 'method_protected_abstract_static' => ['method_abstract', 'method_static', 'method_protected'],
  48846. 'method_private_abstract_static' => ['method_abstract', 'method_static', 'method_private'],
  48847. 'method_public_static' => ['method_static', 'method_public'],
  48848. 'method_protected_static' => ['method_static', 'method_protected'],
  48849. 'method_private_static' => ['method_static', 'method_private'],
  48850. ];
  48851. private const SPECIAL_TYPES = [
  48852. 'construct' => null,
  48853. 'destruct' => null,
  48854. 'magic' => null,
  48855. 'phpunit' => null,
  48856. ];
  48857. private array $typePosition;
  48858. public function isCandidate(Tokens $tokens): bool
  48859. {
  48860. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  48861. }
  48862. public function getDefinition(): FixerDefinitionInterface
  48863. {
  48864. return new FixerDefinition(
  48865. 'Orders the elements of classes/interfaces/traits/enums.',
  48866. [
  48867. new CodeSample(
  48868. '<?php
  48869. final class Example
  48870. {
  48871. use BarTrait;
  48872. use BazTrait;
  48873. const C1 = 1;
  48874. const C2 = 2;
  48875. protected static $protStatProp;
  48876. public static $pubStatProp1;
  48877. public $pubProp1;
  48878. protected $protProp;
  48879. var $pubProp2;
  48880. private static $privStatProp;
  48881. private $privProp;
  48882. public static $pubStatProp2;
  48883. public $pubProp3;
  48884. protected function __construct() {}
  48885. private static function privStatFunc() {}
  48886. public function pubFunc1() {}
  48887. public function __toString() {}
  48888. protected function protFunc() {}
  48889. function pubFunc2() {}
  48890. public static function pubStatFunc1() {}
  48891. public function pubFunc3() {}
  48892. static function pubStatFunc2() {}
  48893. private function privFunc() {}
  48894. public static function pubStatFunc3() {}
  48895. protected static function protStatFunc() {}
  48896. public function __destruct() {}
  48897. }
  48898. '
  48899. ),
  48900. new CodeSample(
  48901. '<?php
  48902. class Example
  48903. {
  48904. public function A(){}
  48905. private function B(){}
  48906. }
  48907. ',
  48908. ['order' => ['method_private', 'method_public']]
  48909. ),
  48910. new CodeSample(
  48911. '<?php
  48912. class Example
  48913. {
  48914. public function D(){}
  48915. public function B(){}
  48916. public function A(){}
  48917. public function C(){}
  48918. }
  48919. ',
  48920. ['order' => ['method_public'], 'sort_algorithm' => self::SORT_ALPHA]
  48921. ),
  48922. new CodeSample(
  48923. '<?php
  48924. class Example
  48925. {
  48926. public function Aa(){}
  48927. public function AA(){}
  48928. public function AwS(){}
  48929. public function AWs(){}
  48930. }
  48931. ',
  48932. ['order' => ['method_public'], 'sort_algorithm' => self::SORT_ALPHA, 'case_sensitive' => true]
  48933. ),
  48934. ],
  48935. 'Accepts a subset of pre-defined element types, special element groups, and custom patterns.
  48936. Element types: `[\''.implode('\', \'', array_keys(self::TYPE_HIERARCHY)).'\']`
  48937. Special element types: `[\''.implode('\', \'', array_keys(self::SPECIAL_TYPES)).'\']`
  48938. Custom values:
  48939. - `method:*`: specify a single method name (e.g. `method:__invoke`) to set the order of that specific method.'
  48940. );
  48941. }
  48942. public function getPriority(): int
  48943. {
  48944. return 65;
  48945. }
  48946. protected function configurePostNormalisation(): void
  48947. {
  48948. $this->typePosition = [];
  48949. $position = 0;
  48950. foreach ($this->configuration['order'] as $type) {
  48951. $this->typePosition[$type] = $position++;
  48952. }
  48953. foreach (self::TYPE_HIERARCHY as $type => $parents) {
  48954. if (isset($this->typePosition[$type])) {
  48955. continue;
  48956. }
  48957. if (null === $parents) {
  48958. $this->typePosition[$type] = null;
  48959. continue;
  48960. }
  48961. foreach ($parents as $parent) {
  48962. if (isset($this->typePosition[$parent])) {
  48963. $this->typePosition[$type] = $this->typePosition[$parent];
  48964. continue 2;
  48965. }
  48966. }
  48967. $this->typePosition[$type] = null;
  48968. }
  48969. $lastPosition = \count($this->configuration['order']);
  48970. foreach ($this->typePosition as &$pos) {
  48971. if (null === $pos) {
  48972. $pos = $lastPosition;
  48973. }
  48974. $pos *= 10;
  48975. }
  48976. }
  48977. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  48978. {
  48979. for ($i = 1, $count = $tokens->count(); $i < $count; ++$i) {
  48980. if (!$tokens[$i]->isClassy()) {
  48981. continue;
  48982. }
  48983. $i = $tokens->getNextTokenOfKind($i, ['{']);
  48984. $elements = $this->getElements($tokens, $i);
  48985. if (0 === \count($elements)) {
  48986. continue;
  48987. }
  48988. $endIndex = $elements[array_key_last($elements)]['end'];
  48989. $sorted = $this->sortElements($elements);
  48990. if ($sorted !== $elements) {
  48991. $this->sortTokens($tokens, $i, $endIndex, $sorted);
  48992. }
  48993. $i = $endIndex;
  48994. }
  48995. }
  48996. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  48997. {
  48998. $builtIns = array_keys(array_merge(self::TYPE_HIERARCHY, self::SPECIAL_TYPES));
  48999. return new FixerConfigurationResolver([
  49000. (new FixerOptionBuilder('order', 'List of strings defining order of elements.'))
  49001. ->setAllowedTypes(['string[]'])
  49002. ->setAllowedValues([
  49003. static function (array $values) use ($builtIns): bool {
  49004. foreach ($values as $value) {
  49005. if (\in_array($value, $builtIns, true)) {
  49006. return true;
  49007. }
  49008. if ('method:' === substr($value, 0, 7)) {
  49009. return true;
  49010. }
  49011. }
  49012. return false;
  49013. },
  49014. ])
  49015. ->setDefault([
  49016. 'use_trait',
  49017. 'case',
  49018. 'constant_public',
  49019. 'constant_protected',
  49020. 'constant_private',
  49021. 'property_public',
  49022. 'property_protected',
  49023. 'property_private',
  49024. 'construct',
  49025. 'destruct',
  49026. 'magic',
  49027. 'phpunit',
  49028. 'method_public',
  49029. 'method_protected',
  49030. 'method_private',
  49031. ])
  49032. ->getOption(),
  49033. (new FixerOptionBuilder('sort_algorithm', 'How multiple occurrences of same type statements should be sorted.'))
  49034. ->setAllowedValues(self::SUPPORTED_SORT_ALGORITHMS)
  49035. ->setDefault(self::SORT_NONE)
  49036. ->getOption(),
  49037. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  49038. ->setAllowedTypes(['bool'])
  49039. ->setDefault(false)
  49040. ->getOption(),
  49041. ]);
  49042. }
  49043. private function getElements(Tokens $tokens, int $startIndex): array
  49044. {
  49045. static $elementTokenKinds = [CT::T_USE_TRAIT, T_CASE, T_CONST, T_VARIABLE, T_FUNCTION];
  49046. ++$startIndex;
  49047. $elements = [];
  49048. while (true) {
  49049. $element = [
  49050. 'start' => $startIndex,
  49051. 'visibility' => 'public',
  49052. 'abstract' => false,
  49053. 'static' => false,
  49054. 'readonly' => false,
  49055. ];
  49056. for ($i = $startIndex;; ++$i) {
  49057. $token = $tokens[$i];
  49058. if ($token->equals('}')) {
  49059. return $elements;
  49060. }
  49061. if ($token->isGivenKind(T_ABSTRACT)) {
  49062. $element['abstract'] = true;
  49063. continue;
  49064. }
  49065. if ($token->isGivenKind(T_STATIC)) {
  49066. $element['static'] = true;
  49067. continue;
  49068. }
  49069. if ($token->isGivenKind(FCT::T_READONLY)) {
  49070. $element['readonly'] = true;
  49071. }
  49072. if ($token->isGivenKind([T_PROTECTED, T_PRIVATE])) {
  49073. $element['visibility'] = strtolower($token->getContent());
  49074. continue;
  49075. }
  49076. if (!$token->isGivenKind($elementTokenKinds)) {
  49077. continue;
  49078. }
  49079. $type = $this->detectElementType($tokens, $i);
  49080. if (\is_array($type)) {
  49081. $element['type'] = $type[0];
  49082. $element['name'] = $type[1];
  49083. } else {
  49084. $element['type'] = $type;
  49085. }
  49086. if ('property' === $element['type']) {
  49087. $element['name'] = $tokens[$i]->getContent();
  49088. } elseif ('constant' === $element['type']) {
  49089. $equalsSignIndex = $tokens->getNextTokenOfKind($i, ['=']);
  49090. $element['name'] = $tokens[$tokens->getPrevMeaningfulToken($equalsSignIndex)]->getContent();
  49091. } elseif (\in_array($element['type'], ['use_trait', 'case', 'method', 'magic', 'construct', 'destruct'], true)) {
  49092. $element['name'] = $tokens[$tokens->getNextMeaningfulToken($i)]->getContent();
  49093. }
  49094. $element['end'] = $this->findElementEnd($tokens, $i);
  49095. break;
  49096. }
  49097. $elements[] = $element;
  49098. $startIndex = $element['end'] + 1;
  49099. }
  49100. }
  49101. private function detectElementType(Tokens $tokens, int $index)
  49102. {
  49103. $token = $tokens[$index];
  49104. if ($token->isGivenKind(CT::T_USE_TRAIT)) {
  49105. return 'use_trait';
  49106. }
  49107. if ($token->isGivenKind(T_CASE)) {
  49108. return 'case';
  49109. }
  49110. if ($token->isGivenKind(T_CONST)) {
  49111. return 'constant';
  49112. }
  49113. if ($token->isGivenKind(T_VARIABLE)) {
  49114. return 'property';
  49115. }
  49116. $nameToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  49117. if ($nameToken->equals([T_STRING, '__construct'], false)) {
  49118. return 'construct';
  49119. }
  49120. if ($nameToken->equals([T_STRING, '__destruct'], false)) {
  49121. return 'destruct';
  49122. }
  49123. if (
  49124. $nameToken->equalsAny([
  49125. [T_STRING, 'setUpBeforeClass'],
  49126. [T_STRING, 'doSetUpBeforeClass'],
  49127. [T_STRING, 'tearDownAfterClass'],
  49128. [T_STRING, 'doTearDownAfterClass'],
  49129. [T_STRING, 'setUp'],
  49130. [T_STRING, 'doSetUp'],
  49131. [T_STRING, 'assertPreConditions'],
  49132. [T_STRING, 'assertPostConditions'],
  49133. [T_STRING, 'tearDown'],
  49134. [T_STRING, 'doTearDown'],
  49135. ], false)
  49136. ) {
  49137. return ['phpunit', strtolower($nameToken->getContent())];
  49138. }
  49139. return str_starts_with($nameToken->getContent(), '__') ? 'magic' : 'method';
  49140. }
  49141. private function findElementEnd(Tokens $tokens, int $index): int
  49142. {
  49143. $index = $tokens->getNextTokenOfKind($index, ['(', '{', ';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]]);
  49144. if ($tokens[$index]->equals('(')) {
  49145. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  49146. $index = $tokens->getNextTokenOfKind($index, ['{', ';']);
  49147. }
  49148. if ($tokens[$index]->equals('{')) {
  49149. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  49150. }
  49151. if ($tokens[$index]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
  49152. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PROPERTY_HOOK, $index);
  49153. }
  49154. for (++$index; $tokens[$index]->isWhitespace(" \t") || $tokens[$index]->isComment(); ++$index);
  49155. --$index;
  49156. return $tokens[$index]->isWhitespace() ? $index - 1 : $index;
  49157. }
  49158. private function sortElements(array $elements): array
  49159. {
  49160. static $phpunitPositions = [
  49161. 'setupbeforeclass' => 1,
  49162. 'dosetupbeforeclass' => 2,
  49163. 'teardownafterclass' => 3,
  49164. 'doteardownafterclass' => 4,
  49165. 'setup' => 5,
  49166. 'dosetup' => 6,
  49167. 'assertpreconditions' => 7,
  49168. 'assertpostconditions' => 8,
  49169. 'teardown' => 9,
  49170. 'doteardown' => 10,
  49171. ];
  49172. $getPositionType = function (array $element) use ($phpunitPositions): int {
  49173. $type = $element['type'];
  49174. if (\in_array($type, ['method', 'magic', 'phpunit'], true) && isset($this->typePosition["method:{$element['name']}"])) {
  49175. return $this->typePosition["method:{$element['name']}"];
  49176. }
  49177. if (\array_key_exists($type, self::SPECIAL_TYPES)) {
  49178. if (isset($this->typePosition[$type])) {
  49179. $position = $this->typePosition[$type];
  49180. if ('phpunit' === $type) {
  49181. $position += $phpunitPositions[$element['name']];
  49182. }
  49183. return $position;
  49184. }
  49185. $type = 'method';
  49186. }
  49187. if (\in_array($type, ['constant', 'property', 'method'], true)) {
  49188. $type .= '_'.$element['visibility'];
  49189. if ($element['abstract']) {
  49190. $type .= '_abstract';
  49191. }
  49192. if ($element['static']) {
  49193. $type .= '_static';
  49194. }
  49195. if ($element['readonly']) {
  49196. $type .= '_readonly';
  49197. }
  49198. }
  49199. return $this->typePosition[$type];
  49200. };
  49201. return Utils::stableSort(
  49202. $elements,
  49203. static fn (array $element): array => ['element' => $element, 'position' => $getPositionType($element)],
  49204. fn (array $a, array $b): int => ($a['position'] === $b['position']) ? $this->sortGroupElements($a['element'], $b['element']) : $a['position'] <=> $b['position'],
  49205. );
  49206. }
  49207. private function sortGroupElements(array $a, array $b): int
  49208. {
  49209. if (self::SORT_ALPHA === $this->configuration['sort_algorithm']) {
  49210. return true === $this->configuration['case_sensitive']
  49211. ? $a['name'] <=> $b['name']
  49212. : strcasecmp($a['name'], $b['name']);
  49213. }
  49214. return $a['start'] <=> $b['start'];
  49215. }
  49216. private function sortTokens(Tokens $tokens, int $startIndex, int $endIndex, array $elements): void
  49217. {
  49218. $replaceTokens = [];
  49219. foreach ($elements as $element) {
  49220. for ($i = $element['start']; $i <= $element['end']; ++$i) {
  49221. $replaceTokens[] = clone $tokens[$i];
  49222. }
  49223. }
  49224. $tokens->overrideRange($startIndex + 1, $endIndex, $replaceTokens);
  49225. }
  49226. }
  49227. <?php
  49228. declare(strict_types=1);
  49229. namespace PhpCsFixer\Fixer\ClassNotation;
  49230. use PhpCsFixer\AbstractFixer;
  49231. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  49232. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  49233. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  49234. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  49235. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  49236. use PhpCsFixer\FixerDefinition\CodeSample;
  49237. use PhpCsFixer\FixerDefinition\FixerDefinition;
  49238. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  49239. use PhpCsFixer\Tokenizer\Token;
  49240. use PhpCsFixer\Tokenizer\Tokens;
  49241. /**
  49242. @phpstan-type
  49243. @phpstan-type
  49244. @implements
  49245. */
  49246. final class OrderedInterfacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  49247. {
  49248. /**
  49249. @use */
  49250. use ConfigurableFixerTrait;
  49251. public const OPTION_DIRECTION = 'direction';
  49252. public const OPTION_ORDER = 'order';
  49253. public const DIRECTION_ASCEND = 'ascend';
  49254. public const DIRECTION_DESCEND = 'descend';
  49255. public const ORDER_ALPHA = 'alpha';
  49256. public const ORDER_LENGTH = 'length';
  49257. private const SUPPORTED_DIRECTION_OPTIONS = [
  49258. self::DIRECTION_ASCEND,
  49259. self::DIRECTION_DESCEND,
  49260. ];
  49261. private const SUPPORTED_ORDER_OPTIONS = [
  49262. self::ORDER_ALPHA,
  49263. self::ORDER_LENGTH,
  49264. ];
  49265. public function getDefinition(): FixerDefinitionInterface
  49266. {
  49267. return new FixerDefinition(
  49268. 'Orders the interfaces in an `implements` or `interface extends` clause.',
  49269. [
  49270. new CodeSample(
  49271. "<?php\n\nfinal class ExampleA implements Gamma, Alpha, Beta {}\n\ninterface ExampleB extends Gamma, Alpha, Beta {}\n"
  49272. ),
  49273. new CodeSample(
  49274. "<?php\n\nfinal class ExampleA implements Gamma, Alpha, Beta {}\n\ninterface ExampleB extends Gamma, Alpha, Beta {}\n",
  49275. [self::OPTION_DIRECTION => self::DIRECTION_DESCEND]
  49276. ),
  49277. new CodeSample(
  49278. "<?php\n\nfinal class ExampleA implements MuchLonger, Short, Longer {}\n\ninterface ExampleB extends MuchLonger, Short, Longer {}\n",
  49279. [self::OPTION_ORDER => self::ORDER_LENGTH]
  49280. ),
  49281. new CodeSample(
  49282. "<?php\n\nfinal class ExampleA implements MuchLonger, Short, Longer {}\n\ninterface ExampleB extends MuchLonger, Short, Longer {}\n",
  49283. [
  49284. self::OPTION_ORDER => self::ORDER_LENGTH,
  49285. self::OPTION_DIRECTION => self::DIRECTION_DESCEND,
  49286. ]
  49287. ),
  49288. new CodeSample(
  49289. "<?php\n\nfinal class ExampleA implements IgnorecaseB, IgNoReCaSeA, IgnoreCaseC {}\n\ninterface ExampleB extends IgnorecaseB, IgNoReCaSeA, IgnoreCaseC {}\n",
  49290. [
  49291. self::OPTION_ORDER => self::ORDER_ALPHA,
  49292. ]
  49293. ),
  49294. new CodeSample(
  49295. "<?php\n\nfinal class ExampleA implements Casesensitivea, CaseSensitiveA, CasesensitiveA {}\n\ninterface ExampleB extends Casesensitivea, CaseSensitiveA, CasesensitiveA {}\n",
  49296. [
  49297. self::OPTION_ORDER => self::ORDER_ALPHA,
  49298. 'case_sensitive' => true,
  49299. ]
  49300. ),
  49301. ],
  49302. );
  49303. }
  49304. public function getPriority(): int
  49305. {
  49306. return 0;
  49307. }
  49308. public function isCandidate(Tokens $tokens): bool
  49309. {
  49310. return $tokens->isTokenKindFound(T_IMPLEMENTS)
  49311. || $tokens->isAllTokenKindsFound([T_INTERFACE, T_EXTENDS]);
  49312. }
  49313. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  49314. {
  49315. foreach ($tokens as $index => $token) {
  49316. if (!$token->isGivenKind(T_IMPLEMENTS)) {
  49317. if (!$token->isGivenKind(T_EXTENDS)) {
  49318. continue;
  49319. }
  49320. $nameTokenIndex = $tokens->getPrevMeaningfulToken($index);
  49321. $interfaceTokenIndex = $tokens->getPrevMeaningfulToken($nameTokenIndex);
  49322. $interfaceToken = $tokens[$interfaceTokenIndex];
  49323. if (!$interfaceToken->isGivenKind(T_INTERFACE)) {
  49324. continue;
  49325. }
  49326. }
  49327. $implementsStart = $index + 1;
  49328. $implementsEnd = $tokens->getPrevMeaningfulToken($tokens->getNextTokenOfKind($implementsStart, ['{']));
  49329. $interfaces = $this->getInterfaces($tokens, $implementsStart, $implementsEnd);
  49330. if (1 === \count($interfaces)) {
  49331. continue;
  49332. }
  49333. foreach ($interfaces as $interfaceIndex => $interface) {
  49334. $interfaceTokens = Tokens::fromArray($interface);
  49335. $normalized = '';
  49336. $actualInterfaceIndex = $interfaceTokens->getNextMeaningfulToken(-1);
  49337. while ($interfaceTokens->offsetExists($actualInterfaceIndex)) {
  49338. $token = $interfaceTokens[$actualInterfaceIndex];
  49339. if ($token->isComment() || $token->isWhitespace()) {
  49340. break;
  49341. }
  49342. $normalized .= str_replace('\\', ' ', $token->getContent());
  49343. ++$actualInterfaceIndex;
  49344. }
  49345. $interfaces[$interfaceIndex] = [
  49346. 'tokens' => $interface,
  49347. 'normalized' => $normalized,
  49348. 'originalIndex' => $interfaceIndex,
  49349. ];
  49350. }
  49351. usort($interfaces, function (array $first, array $second): int {
  49352. $score = self::ORDER_LENGTH === $this->configuration[self::OPTION_ORDER]
  49353. ? \strlen($first['normalized']) - \strlen($second['normalized'])
  49354. : (
  49355. true === $this->configuration['case_sensitive']
  49356. ? $first['normalized'] <=> $second['normalized']
  49357. : strcasecmp($first['normalized'], $second['normalized'])
  49358. );
  49359. if (self::DIRECTION_DESCEND === $this->configuration[self::OPTION_DIRECTION]) {
  49360. $score *= -1;
  49361. }
  49362. return $score;
  49363. });
  49364. $changed = false;
  49365. foreach ($interfaces as $interfaceIndex => $interface) {
  49366. if ($interface['originalIndex'] !== $interfaceIndex) {
  49367. $changed = true;
  49368. break;
  49369. }
  49370. }
  49371. if (!$changed) {
  49372. continue;
  49373. }
  49374. $newTokens = array_shift($interfaces)['tokens'];
  49375. foreach ($interfaces as $interface) {
  49376. array_push($newTokens, new Token(','), ...$interface['tokens']);
  49377. }
  49378. $tokens->overrideRange($implementsStart, $implementsEnd, $newTokens);
  49379. }
  49380. }
  49381. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  49382. {
  49383. return new FixerConfigurationResolver([
  49384. (new FixerOptionBuilder(self::OPTION_ORDER, 'How the interfaces should be ordered.'))
  49385. ->setAllowedValues(self::SUPPORTED_ORDER_OPTIONS)
  49386. ->setDefault(self::ORDER_ALPHA)
  49387. ->getOption(),
  49388. (new FixerOptionBuilder(self::OPTION_DIRECTION, 'Which direction the interfaces should be ordered.'))
  49389. ->setAllowedValues(self::SUPPORTED_DIRECTION_OPTIONS)
  49390. ->setDefault(self::DIRECTION_ASCEND)
  49391. ->getOption(),
  49392. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  49393. ->setAllowedTypes(['bool'])
  49394. ->setDefault(false)
  49395. ->getOption(),
  49396. ]);
  49397. }
  49398. private function getInterfaces(Tokens $tokens, int $implementsStart, int $implementsEnd): array
  49399. {
  49400. $interfaces = [];
  49401. $interfaceIndex = 0;
  49402. for ($i = $implementsStart; $i <= $implementsEnd; ++$i) {
  49403. if ($tokens[$i]->equals(',')) {
  49404. ++$interfaceIndex;
  49405. $interfaces[$interfaceIndex] = [];
  49406. continue;
  49407. }
  49408. $interfaces[$interfaceIndex][] = $tokens[$i];
  49409. }
  49410. return $interfaces;
  49411. }
  49412. }
  49413. <?php
  49414. declare(strict_types=1);
  49415. namespace PhpCsFixer\Fixer\ClassNotation;
  49416. use PhpCsFixer\AbstractFixer;
  49417. use PhpCsFixer\FixerDefinition\CodeSample;
  49418. use PhpCsFixer\FixerDefinition\FixerDefinition;
  49419. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  49420. use PhpCsFixer\Tokenizer\Token;
  49421. use PhpCsFixer\Tokenizer\Tokens;
  49422. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  49423. final class NoPhp4ConstructorFixer extends AbstractFixer
  49424. {
  49425. public function getDefinition(): FixerDefinitionInterface
  49426. {
  49427. return new FixerDefinition(
  49428. 'Convert PHP4-style constructors to `__construct`.',
  49429. [
  49430. new CodeSample('<?php
  49431. class Foo
  49432. {
  49433. public function Foo($bar)
  49434. {
  49435. }
  49436. }
  49437. '),
  49438. ],
  49439. null,
  49440. 'Risky when old style constructor being fixed is overridden or overrides parent one.'
  49441. );
  49442. }
  49443. public function getPriority(): int
  49444. {
  49445. return 75;
  49446. }
  49447. public function isCandidate(Tokens $tokens): bool
  49448. {
  49449. return $tokens->isTokenKindFound(T_CLASS);
  49450. }
  49451. public function isRisky(): bool
  49452. {
  49453. return true;
  49454. }
  49455. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  49456. {
  49457. $tokensAnalyzer = new TokensAnalyzer($tokens);
  49458. $classes = array_keys($tokens->findGivenKind(T_CLASS));
  49459. $numClasses = \count($classes);
  49460. for ($i = 0; $i < $numClasses; ++$i) {
  49461. $index = $classes[$i];
  49462. if ($tokensAnalyzer->isAnonymousClass($index)) {
  49463. continue;
  49464. }
  49465. $nspIndex = $tokens->getPrevTokenOfKind($index, [[T_NAMESPACE, 'namespace']]);
  49466. if (null !== $nspIndex) {
  49467. $nspIndex = $tokens->getNextMeaningfulToken($nspIndex);
  49468. if (!$tokens[$nspIndex]->equals('{')) {
  49469. $nspIndex = $tokens->getNextTokenOfKind($nspIndex, [';', '{']);
  49470. if ($tokens[$nspIndex]->equals(';')) {
  49471. break;
  49472. }
  49473. $nspEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nspIndex);
  49474. if ($index < $nspEnd) {
  49475. for ($j = $i + 1; $j < $numClasses; ++$j) {
  49476. if ($classes[$j] < $nspEnd) {
  49477. ++$i;
  49478. }
  49479. }
  49480. continue;
  49481. }
  49482. }
  49483. }
  49484. $classNameIndex = $tokens->getNextMeaningfulToken($index);
  49485. $className = $tokens[$classNameIndex]->getContent();
  49486. $classStart = $tokens->getNextTokenOfKind($classNameIndex, ['{']);
  49487. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
  49488. $this->fixConstructor($tokens, $className, $classStart, $classEnd);
  49489. $this->fixParent($tokens, $classStart, $classEnd);
  49490. }
  49491. }
  49492. private function fixConstructor(Tokens $tokens, string $className, int $classStart, int $classEnd): void
  49493. {
  49494. $php4 = $this->findFunction($tokens, $className, $classStart, $classEnd);
  49495. if (null === $php4) {
  49496. return;
  49497. }
  49498. if (isset($php4['modifiers'][T_ABSTRACT]) || isset($php4['modifiers'][T_STATIC])) {
  49499. return;
  49500. }
  49501. $php5 = $this->findFunction($tokens, '__construct', $classStart, $classEnd);
  49502. if (null === $php5) {
  49503. $tokens[$php4['nameIndex']] = new Token([T_STRING, '__construct']);
  49504. $this->fixInfiniteRecursion($tokens, $php4['bodyIndex'], $php4['endIndex']);
  49505. return;
  49506. }
  49507. [$sequences, $case] = $this->getWrapperMethodSequence($tokens, '__construct', $php4['startIndex'], $php4['bodyIndex']);
  49508. foreach ($sequences as $seq) {
  49509. if (null !== $tokens->findSequence($seq, $php4['bodyIndex'] - 1, $php4['endIndex'], $case)) {
  49510. for ($i = $php4['startIndex']; $i <= $php4['endIndex']; ++$i) {
  49511. $tokens->clearAt($i);
  49512. }
  49513. return;
  49514. }
  49515. }
  49516. [$sequences, $case] = $this->getWrapperMethodSequence($tokens, $className, $php4['startIndex'], $php4['bodyIndex']);
  49517. foreach ($sequences as $seq) {
  49518. if (null !== $tokens->findSequence($seq, $php5['bodyIndex'] - 1, $php5['endIndex'], $case)) {
  49519. for ($i = $php5['startIndex']; $i <= $php5['endIndex']; ++$i) {
  49520. $tokens->clearAt($i);
  49521. }
  49522. $tokens[$php4['nameIndex']] = new Token([T_STRING, '__construct']);
  49523. return;
  49524. }
  49525. }
  49526. }
  49527. private function fixParent(Tokens $tokens, int $classStart, int $classEnd): void
  49528. {
  49529. foreach ($tokens->findGivenKind(T_EXTENDS) as $index => $token) {
  49530. $parentIndex = $tokens->getNextMeaningfulToken($index);
  49531. $parentClass = $tokens[$parentIndex]->getContent();
  49532. $parentSeq = $tokens->findSequence([
  49533. [T_STRING],
  49534. [T_DOUBLE_COLON],
  49535. [T_STRING, $parentClass],
  49536. '(',
  49537. ], $classStart, $classEnd, [2 => false]);
  49538. if (null !== $parentSeq) {
  49539. $parentSeq = array_keys($parentSeq);
  49540. if ($tokens[$parentSeq[0]]->equalsAny([[T_STRING, 'parent'], [T_STRING, $parentClass]], false)) {
  49541. $tokens[$parentSeq[0]] = new Token([T_STRING, 'parent']);
  49542. $tokens[$parentSeq[2]] = new Token([T_STRING, '__construct']);
  49543. }
  49544. }
  49545. foreach (Token::getObjectOperatorKinds() as $objectOperatorKind) {
  49546. $parentSeq = $tokens->findSequence([
  49547. [T_VARIABLE, '$this'],
  49548. [$objectOperatorKind],
  49549. [T_STRING, $parentClass],
  49550. '(',
  49551. ], $classStart, $classEnd, [2 => false]);
  49552. if (null !== $parentSeq) {
  49553. $parentSeq = array_keys($parentSeq);
  49554. $tokens[$parentSeq[0]] = new Token([
  49555. T_STRING,
  49556. 'parent',
  49557. ]);
  49558. $tokens[$parentSeq[1]] = new Token([
  49559. T_DOUBLE_COLON,
  49560. '::',
  49561. ]);
  49562. $tokens[$parentSeq[2]] = new Token([T_STRING, '__construct']);
  49563. }
  49564. }
  49565. }
  49566. }
  49567. private function fixInfiniteRecursion(Tokens $tokens, int $start, int $end): void
  49568. {
  49569. foreach (Token::getObjectOperatorKinds() as $objectOperatorKind) {
  49570. $seq = [
  49571. [T_VARIABLE, '$this'],
  49572. [$objectOperatorKind],
  49573. [T_STRING, '__construct'],
  49574. ];
  49575. while (true) {
  49576. $callSeq = $tokens->findSequence($seq, $start, $end, [2 => false]);
  49577. if (null === $callSeq) {
  49578. return;
  49579. }
  49580. $callSeq = array_keys($callSeq);
  49581. $tokens[$callSeq[0]] = new Token([T_STRING, 'parent']);
  49582. $tokens[$callSeq[1]] = new Token([T_DOUBLE_COLON, '::']);
  49583. }
  49584. }
  49585. }
  49586. private function getWrapperMethodSequence(Tokens $tokens, string $method, int $startIndex, int $bodyIndex): array
  49587. {
  49588. $sequences = [];
  49589. foreach (Token::getObjectOperatorKinds() as $objectOperatorKind) {
  49590. $seq = [
  49591. '{',
  49592. [T_VARIABLE, '$this'],
  49593. [$objectOperatorKind],
  49594. [T_STRING, $method],
  49595. '(',
  49596. ];
  49597. $index = $startIndex;
  49598. while (true) {
  49599. $index = $tokens->getNextTokenOfKind($index, [[T_VARIABLE]]);
  49600. if (null === $index || $index >= $bodyIndex) {
  49601. break;
  49602. }
  49603. if (\count($seq) > 5) {
  49604. $seq[] = ',';
  49605. }
  49606. $seq[] = [T_VARIABLE, $tokens[$index]->getContent()];
  49607. }
  49608. $seq[] = ')';
  49609. $seq[] = ';';
  49610. $seq[] = '}';
  49611. $sequences[] = $seq;
  49612. }
  49613. return [$sequences, [3 => false]];
  49614. }
  49615. private function findFunction(Tokens $tokens, string $name, int $startIndex, int $endIndex): ?array
  49616. {
  49617. $function = $tokens->findSequence([
  49618. [T_FUNCTION],
  49619. [T_STRING, $name],
  49620. '(',
  49621. ], $startIndex, $endIndex, false);
  49622. if (null === $function) {
  49623. return null;
  49624. }
  49625. $function = array_keys($function);
  49626. $possibleModifiers = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_STATIC, T_ABSTRACT, T_FINAL];
  49627. $modifiers = [];
  49628. $prevBlock = $tokens->getPrevMeaningfulToken($function[0]);
  49629. while (null !== $prevBlock && $tokens[$prevBlock]->isGivenKind($possibleModifiers)) {
  49630. $modifiers[$tokens[$prevBlock]->getId()] = $prevBlock;
  49631. $prevBlock = $tokens->getPrevMeaningfulToken($prevBlock);
  49632. }
  49633. if (isset($modifiers[T_ABSTRACT])) {
  49634. $bodyStart = null;
  49635. $funcEnd = $tokens->getNextTokenOfKind($function[2], [';']);
  49636. } else {
  49637. $bodyStart = $tokens->getNextTokenOfKind($function[2], ['{']);
  49638. $funcEnd = null !== $bodyStart ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $bodyStart) : null;
  49639. }
  49640. return [
  49641. 'nameIndex' => $function[1],
  49642. 'startIndex' => $prevBlock + 1,
  49643. 'endIndex' => $funcEnd,
  49644. 'bodyIndex' => $bodyStart,
  49645. 'modifiers' => $modifiers,
  49646. ];
  49647. }
  49648. }
  49649. <?php
  49650. declare(strict_types=1);
  49651. namespace PhpCsFixer\Fixer\ClassNotation;
  49652. use PhpCsFixer\AbstractFixer;
  49653. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  49654. use PhpCsFixer\DocBlock\DocBlock;
  49655. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  49656. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  49657. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  49658. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  49659. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  49660. use PhpCsFixer\FixerDefinition\CodeSample;
  49661. use PhpCsFixer\FixerDefinition\FixerDefinition;
  49662. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  49663. use PhpCsFixer\Preg;
  49664. use PhpCsFixer\Tokenizer\CT;
  49665. use PhpCsFixer\Tokenizer\FCT;
  49666. use PhpCsFixer\Tokenizer\Token;
  49667. use PhpCsFixer\Tokenizer\Tokens;
  49668. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  49669. use PhpCsFixer\Utils;
  49670. use Symfony\Component\OptionsResolver\Options;
  49671. /**
  49672. @phpstan-type
  49673. @phpstan-type
  49674. @implements
  49675. */
  49676. final class FinalInternalClassFixer extends AbstractFixer implements ConfigurableFixerInterface
  49677. {
  49678. /**
  49679. @use */
  49680. use ConfigurableFixerTrait;
  49681. private const DEFAULTS = [
  49682. 'include' => [
  49683. 'internal',
  49684. ],
  49685. 'exclude' => [
  49686. 'final',
  49687. 'Entity',
  49688. 'ORM\Entity',
  49689. 'ORM\Mapping\Entity',
  49690. 'Mapping\Entity',
  49691. 'Document',
  49692. 'ODM\Document',
  49693. ],
  49694. ];
  49695. private const CLASS_CANDIDATE_ACCEPT_TYPES = [
  49696. CT::T_ATTRIBUTE_CLOSE,
  49697. T_DOC_COMMENT,
  49698. T_COMMENT,
  49699. FCT::T_READONLY,
  49700. ];
  49701. private bool $checkAttributes;
  49702. public function __construct()
  49703. {
  49704. parent::__construct();
  49705. $this->checkAttributes = \PHP_VERSION_ID >= 8_00_00;
  49706. }
  49707. public function getDefinition(): FixerDefinitionInterface
  49708. {
  49709. return new FixerDefinition(
  49710. 'Internal classes should be `final`.',
  49711. [
  49712. new CodeSample("<?php\n/**\n * @internal\n */\nclass Sample\n{\n}\n"),
  49713. new CodeSample(
  49714. "<?php\n/**\n * @CUSTOM\n */\nclass A{}\n\n/**\n * @CUSTOM\n * @not-fix\n */\nclass B{}\n",
  49715. [
  49716. 'include' => ['@Custom'],
  49717. 'exclude' => ['@not-fix'],
  49718. ]
  49719. ),
  49720. ],
  49721. null,
  49722. 'Changing classes to `final` might cause code execution to break.'
  49723. );
  49724. }
  49725. public function getPriority(): int
  49726. {
  49727. return 67;
  49728. }
  49729. public function isCandidate(Tokens $tokens): bool
  49730. {
  49731. return $tokens->isTokenKindFound(T_CLASS);
  49732. }
  49733. public function isRisky(): bool
  49734. {
  49735. return true;
  49736. }
  49737. protected function configurePostNormalisation(): void
  49738. {
  49739. $this->assertConfigHasNoConflicts();
  49740. }
  49741. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  49742. {
  49743. $tokensAnalyzer = new TokensAnalyzer($tokens);
  49744. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  49745. if (!$tokens[$index]->isGivenKind(T_CLASS) || !$this->isClassCandidate($tokensAnalyzer, $tokens, $index)) {
  49746. continue;
  49747. }
  49748. $tokens->insertSlices([
  49749. $index => [
  49750. new Token([T_FINAL, 'final']),
  49751. new Token([T_WHITESPACE, ' ']),
  49752. ],
  49753. ]);
  49754. }
  49755. }
  49756. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  49757. {
  49758. $annotationsAsserts = [static function (array $values): bool {
  49759. foreach ($values as $value) {
  49760. if ('' === $value) {
  49761. return false;
  49762. }
  49763. }
  49764. return true;
  49765. }];
  49766. $annotationsNormalizer = static function (Options $options, array $value): array {
  49767. $newValue = [];
  49768. foreach ($value as $key) {
  49769. if (str_starts_with($key, '@')) {
  49770. $key = substr($key, 1);
  49771. }
  49772. $newValue[strtolower($key)] = true;
  49773. }
  49774. return $newValue;
  49775. };
  49776. return new FixerConfigurationResolver([
  49777. (new FixerOptionBuilder('annotation_include', 'Class level attribute or annotation tags that must be set in order to fix the class (case insensitive).'))
  49778. ->setAllowedTypes(['string[]'])
  49779. ->setAllowedValues($annotationsAsserts)
  49780. ->setDefault(
  49781. array_map(
  49782. static fn (string $string) => '@'.$string,
  49783. self::DEFAULTS['include'],
  49784. ),
  49785. )
  49786. ->setNormalizer($annotationsNormalizer)
  49787. ->setDeprecationMessage('Use `include` to configure PHPDoc annotations tags and attributes.')
  49788. ->getOption(),
  49789. (new FixerOptionBuilder('annotation_exclude', 'Class level attribute or annotation tags that must be omitted to fix the class, even if all of the white list ones are used as well (case insensitive).'))
  49790. ->setAllowedTypes(['string[]'])
  49791. ->setAllowedValues($annotationsAsserts)
  49792. ->setDefault(
  49793. array_map(
  49794. static fn (string $string) => '@'.$string,
  49795. self::DEFAULTS['exclude'],
  49796. ),
  49797. )
  49798. ->setNormalizer($annotationsNormalizer)
  49799. ->setDeprecationMessage('Use `exclude` to configure PHPDoc annotations tags and attributes.')
  49800. ->getOption(),
  49801. (new FixerOptionBuilder('include', 'Class level attribute or annotation tags that must be set in order to fix the class (case insensitive).'))
  49802. ->setAllowedTypes(['string[]'])
  49803. ->setAllowedValues($annotationsAsserts)
  49804. ->setDefault(self::DEFAULTS['include'])
  49805. ->setNormalizer($annotationsNormalizer)
  49806. ->getOption(),
  49807. (new FixerOptionBuilder('exclude', 'Class level attribute or annotation tags that must be omitted to fix the class, even if all of the white list ones are used as well (case insensitive).'))
  49808. ->setAllowedTypes(['string[]'])
  49809. ->setAllowedValues($annotationsAsserts)
  49810. ->setDefault(self::DEFAULTS['exclude'])
  49811. ->setNormalizer($annotationsNormalizer)
  49812. ->getOption(),
  49813. (new FixerOptionBuilder('consider_absent_docblock_as_internal_class', 'Whether classes without any DocBlock should be fixed to final.'))
  49814. ->setAllowedTypes(['bool'])
  49815. ->setDefault(false)
  49816. ->getOption(),
  49817. ]);
  49818. }
  49819. private function isClassCandidate(TokensAnalyzer $tokensAnalyzer, Tokens $tokens, int $index): bool
  49820. {
  49821. if ($tokensAnalyzer->isAnonymousClass($index)) {
  49822. return false;
  49823. }
  49824. $modifiers = $tokensAnalyzer->getClassyModifiers($index);
  49825. if (isset($modifiers['final']) || isset($modifiers['abstract'])) {
  49826. return false;
  49827. }
  49828. $decisions = [];
  49829. $currentIndex = $index;
  49830. while (null !== $currentIndex) {
  49831. $currentIndex = $tokens->getPrevNonWhitespace($currentIndex);
  49832. if (!$tokens[$currentIndex]->isGivenKind(self::CLASS_CANDIDATE_ACCEPT_TYPES)) {
  49833. break;
  49834. }
  49835. if ($this->checkAttributes && $tokens[$currentIndex]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  49836. $attributeStartIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $currentIndex);
  49837. $decisions[] = $this->isClassCandidateBasedOnAttribute($tokens, $attributeStartIndex, $currentIndex);
  49838. $currentIndex = $attributeStartIndex;
  49839. }
  49840. if ($tokens[$currentIndex]->isGivenKind([T_DOC_COMMENT])) {
  49841. $decisions[] = $this->isClassCandidateBasedOnPhpDoc($tokens, $currentIndex);
  49842. }
  49843. }
  49844. if (\in_array(false, $decisions, true)) {
  49845. return false;
  49846. }
  49847. return \in_array(true, $decisions, true)
  49848. || ([] === $decisions && true === $this->configuration['consider_absent_docblock_as_internal_class']);
  49849. }
  49850. private function isClassCandidateBasedOnPhpDoc(Tokens $tokens, int $index): ?bool
  49851. {
  49852. $doc = new DocBlock($tokens[$index]->getContent());
  49853. $tags = [];
  49854. foreach ($doc->getAnnotations() as $annotation) {
  49855. if (!Preg::match('/@([^\(\s]+)/', $annotation->getContent(), $matches)) {
  49856. continue;
  49857. }
  49858. $tag = strtolower(substr(array_shift($matches), 1));
  49859. $tags[$tag] = true;
  49860. }
  49861. if (\count(array_intersect_key($this->configuration['exclude'], $tags)) > 0) {
  49862. return false;
  49863. }
  49864. if ($this->isConfiguredAsInclude($tags)) {
  49865. return true;
  49866. }
  49867. return null;
  49868. }
  49869. private function isClassCandidateBasedOnAttribute(Tokens $tokens, int $startIndex, int $endIndex): ?bool
  49870. {
  49871. $attributeCandidates = [];
  49872. $attributeString = '';
  49873. $currentIndex = $startIndex;
  49874. while ($currentIndex < $endIndex && null !== ($currentIndex = $tokens->getNextMeaningfulToken($currentIndex))) {
  49875. if (!$tokens[$currentIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR])) {
  49876. if ('' !== $attributeString) {
  49877. $attributeCandidates[$attributeString] = true;
  49878. $attributeString = '';
  49879. }
  49880. continue;
  49881. }
  49882. $attributeString .= strtolower($tokens[$currentIndex]->getContent());
  49883. }
  49884. if (\count(array_intersect_key($this->configuration['exclude'], $attributeCandidates)) > 0) {
  49885. return false;
  49886. }
  49887. if ($this->isConfiguredAsInclude($attributeCandidates)) {
  49888. return true;
  49889. }
  49890. return null;
  49891. }
  49892. private function isConfiguredAsInclude(array $attributes): bool
  49893. {
  49894. if (0 === \count($this->configuration['include'])) {
  49895. return true;
  49896. }
  49897. return \count(array_intersect_key($this->configuration['include'], $attributes)) > 0;
  49898. }
  49899. private function assertConfigHasNoConflicts(): void
  49900. {
  49901. foreach (['include' => 'annotation_include', 'exclude' => 'annotation_exclude'] as $newConfigKey => $oldConfigKey) {
  49902. $defaults = [];
  49903. foreach (self::DEFAULTS[$newConfigKey] as $foo) {
  49904. $defaults[strtolower($foo)] = true;
  49905. }
  49906. $newConfigIsSet = $this->configuration[$newConfigKey] !== $defaults;
  49907. $oldConfigIsSet = $this->configuration[$oldConfigKey] !== $defaults;
  49908. if ($newConfigIsSet && $oldConfigIsSet) {
  49909. throw new InvalidFixerConfigurationException($this->getName(), \sprintf('Configuration cannot contain deprecated option "%s" and new option "%s".', $oldConfigKey, $newConfigKey));
  49910. }
  49911. if ($oldConfigIsSet) {
  49912. $this->configuration[$newConfigKey] = $this->configuration[$oldConfigKey];
  49913. $this->checkAttributes = false;
  49914. }
  49915. unset($this->configuration[$oldConfigKey]);
  49916. }
  49917. $intersect = array_intersect_assoc($this->configuration['include'], $this->configuration['exclude']);
  49918. if (\count($intersect) > 0) {
  49919. throw new InvalidFixerConfigurationException($this->getName(), \sprintf('Annotation cannot be used in both "include" and "exclude" list, got duplicates: %s.', Utils::naturalLanguageJoin(array_keys($intersect))));
  49920. }
  49921. }
  49922. }
  49923. <?php
  49924. declare(strict_types=1);
  49925. namespace PhpCsFixer\Fixer\ClassNotation;
  49926. use PhpCsFixer\AbstractFixer;
  49927. use PhpCsFixer\FixerDefinition\CodeSample;
  49928. use PhpCsFixer\FixerDefinition\FixerDefinition;
  49929. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  49930. use PhpCsFixer\Tokenizer\Tokens;
  49931. final class NoNullPropertyInitializationFixer extends AbstractFixer
  49932. {
  49933. public function getDefinition(): FixerDefinitionInterface
  49934. {
  49935. return new FixerDefinition(
  49936. 'Properties MUST not be explicitly initialized with `null` except when they have a type declaration (PHP 7.4).',
  49937. [
  49938. new CodeSample(
  49939. '<?php
  49940. class Foo {
  49941. public $foo = null;
  49942. }
  49943. '
  49944. ),
  49945. new CodeSample(
  49946. '<?php
  49947. class Foo {
  49948. public static $foo = null;
  49949. }
  49950. '
  49951. ),
  49952. ]
  49953. );
  49954. }
  49955. public function isCandidate(Tokens $tokens): bool
  49956. {
  49957. return $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT]) && $tokens->isAnyTokenKindsFound([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR, T_STATIC]);
  49958. }
  49959. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  49960. {
  49961. $inClass = [];
  49962. $classLevel = 0;
  49963. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  49964. if ($tokens[$index]->isGivenKind([T_CLASS, T_TRAIT])) {
  49965. ++$classLevel;
  49966. $inClass[$classLevel] = 1;
  49967. $index = $tokens->getNextTokenOfKind($index, ['{']);
  49968. continue;
  49969. }
  49970. if (0 === $classLevel) {
  49971. continue;
  49972. }
  49973. if ($tokens[$index]->equals('{')) {
  49974. ++$inClass[$classLevel];
  49975. continue;
  49976. }
  49977. if ($tokens[$index]->equals('}')) {
  49978. --$inClass[$classLevel];
  49979. if (0 === $inClass[$classLevel]) {
  49980. unset($inClass[$classLevel]);
  49981. --$classLevel;
  49982. }
  49983. continue;
  49984. }
  49985. if (1 !== $inClass[$classLevel]) {
  49986. continue;
  49987. }
  49988. if (!$tokens[$index]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR, T_STATIC])) {
  49989. continue;
  49990. }
  49991. while (true) {
  49992. $varTokenIndex = $index = $tokens->getNextMeaningfulToken($index);
  49993. if ($tokens[$index]->isGivenKind(T_STATIC)) {
  49994. $varTokenIndex = $index = $tokens->getNextMeaningfulToken($index);
  49995. }
  49996. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  49997. break;
  49998. }
  49999. $index = $tokens->getNextMeaningfulToken($index);
  50000. if ($tokens[$index]->equals('=')) {
  50001. $index = $tokens->getNextMeaningfulToken($index);
  50002. if ($tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  50003. $index = $tokens->getNextMeaningfulToken($index);
  50004. }
  50005. if ($tokens[$index]->equals([T_STRING, 'null'], false)) {
  50006. for ($i = $varTokenIndex + 1; $i <= $index; ++$i) {
  50007. if (
  50008. !($tokens[$i]->isWhitespace() && str_contains($tokens[$i]->getContent(), "\n"))
  50009. && !$tokens[$i]->isComment()
  50010. ) {
  50011. $tokens->clearAt($i);
  50012. }
  50013. }
  50014. }
  50015. ++$index;
  50016. }
  50017. if (!$tokens[$index]->equals(',')) {
  50018. break;
  50019. }
  50020. }
  50021. }
  50022. }
  50023. }
  50024. <?php
  50025. declare(strict_types=1);
  50026. namespace PhpCsFixer\Fixer\ClassNotation;
  50027. use PhpCsFixer\AbstractProxyFixer;
  50028. use PhpCsFixer\FixerDefinition\CodeSample;
  50029. use PhpCsFixer\FixerDefinition\FixerDefinition;
  50030. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  50031. final class FinalClassFixer extends AbstractProxyFixer
  50032. {
  50033. public function getDefinition(): FixerDefinitionInterface
  50034. {
  50035. return new FixerDefinition(
  50036. 'All classes must be final, except abstract ones and Doctrine entities.',
  50037. [
  50038. new CodeSample(
  50039. '<?php
  50040. class MyApp {}
  50041. '
  50042. ),
  50043. ],
  50044. 'No exception and no configuration are intentional. Beside Doctrine entities and of course abstract classes, there is no single reason not to declare all classes final. '
  50045. .'If you want to subclass a class, mark the parent class as abstract and create two child classes, one empty if necessary: you\'ll gain much more fine grained type-hinting. '
  50046. .'If you need to mock a standalone class, create an interface, or maybe it\'s a value-object that shouldn\'t be mocked at all. '
  50047. .'If you need to extend a standalone class, create an interface and use the Composite pattern. '
  50048. .'If these rules are too strict for you, you can use `FinalInternalClassFixer` instead.',
  50049. 'Risky when subclassing non-abstract classes.'
  50050. );
  50051. }
  50052. public function getPriority(): int
  50053. {
  50054. return parent::getPriority();
  50055. }
  50056. protected function createProxyFixers(): array
  50057. {
  50058. $fixer = new FinalInternalClassFixer();
  50059. $fixer->configure([
  50060. 'include' => [],
  50061. 'consider_absent_docblock_as_internal_class' => true,
  50062. ]);
  50063. return [$fixer];
  50064. }
  50065. }
  50066. <?php
  50067. declare(strict_types=1);
  50068. namespace PhpCsFixer\Fixer\ClassNotation;
  50069. use PhpCsFixer\AbstractFixer;
  50070. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  50071. use PhpCsFixer\FixerDefinition\CodeSample;
  50072. use PhpCsFixer\FixerDefinition\FixerDefinition;
  50073. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  50074. use PhpCsFixer\Tokenizer\Token;
  50075. use PhpCsFixer\Tokenizer\Tokens;
  50076. final class NoBlankLinesAfterClassOpeningFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  50077. {
  50078. public function isCandidate(Tokens $tokens): bool
  50079. {
  50080. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  50081. }
  50082. public function getDefinition(): FixerDefinitionInterface
  50083. {
  50084. return new FixerDefinition(
  50085. 'There should be no empty lines after class opening brace.',
  50086. [
  50087. new CodeSample(
  50088. '<?php
  50089. final class Sample
  50090. {
  50091. protected function foo()
  50092. {
  50093. }
  50094. }
  50095. '
  50096. ),
  50097. ]
  50098. );
  50099. }
  50100. public function getPriority(): int
  50101. {
  50102. return 0;
  50103. }
  50104. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  50105. {
  50106. foreach ($tokens as $index => $token) {
  50107. if (!$token->isClassy()) {
  50108. continue;
  50109. }
  50110. $startBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
  50111. if (!$tokens[$startBraceIndex + 1]->isWhitespace()) {
  50112. continue;
  50113. }
  50114. $this->fixWhitespace($tokens, $startBraceIndex + 1);
  50115. }
  50116. }
  50117. private function fixWhitespace(Tokens $tokens, int $index): void
  50118. {
  50119. $content = $tokens[$index]->getContent();
  50120. if (substr_count($content, "\n") > 1) {
  50121. $tokens[$index] = new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding().substr($content, strrpos($content, "\n") + 1)]);
  50122. }
  50123. }
  50124. }
  50125. <?php
  50126. declare(strict_types=1);
  50127. namespace PhpCsFixer\Fixer\ClassNotation;
  50128. use PhpCsFixer\AbstractFixer;
  50129. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  50130. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  50131. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  50132. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  50133. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  50134. use PhpCsFixer\FixerDefinition\CodeSample;
  50135. use PhpCsFixer\FixerDefinition\FixerDefinition;
  50136. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  50137. use PhpCsFixer\Tokenizer\FCT;
  50138. use PhpCsFixer\Tokenizer\Token;
  50139. use PhpCsFixer\Tokenizer\Tokens;
  50140. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  50141. /**
  50142. @phpstan-type
  50143. @phpstan-type
  50144. @implements
  50145. */
  50146. final class NoUnneededFinalMethodFixer extends AbstractFixer implements ConfigurableFixerInterface
  50147. {
  50148. /**
  50149. @use */
  50150. use ConfigurableFixerTrait;
  50151. public function getDefinition(): FixerDefinitionInterface
  50152. {
  50153. return new FixerDefinition(
  50154. 'Removes `final` from methods where possible.',
  50155. [
  50156. new CodeSample(
  50157. '<?php
  50158. final class Foo
  50159. {
  50160. final public function foo1() {}
  50161. final protected function bar() {}
  50162. final private function baz() {}
  50163. }
  50164. class Bar
  50165. {
  50166. final private function bar1() {}
  50167. }
  50168. '
  50169. ),
  50170. new CodeSample(
  50171. '<?php
  50172. final class Foo
  50173. {
  50174. final private function baz() {}
  50175. }
  50176. class Bar
  50177. {
  50178. final private function bar1() {}
  50179. }
  50180. ',
  50181. ['private_methods' => false]
  50182. ),
  50183. ],
  50184. null,
  50185. 'Risky when child class overrides a `private` method.'
  50186. );
  50187. }
  50188. public function isCandidate(Tokens $tokens): bool
  50189. {
  50190. if (!$tokens->isAllTokenKindsFound([T_FINAL, T_FUNCTION])) {
  50191. return false;
  50192. }
  50193. return $tokens->isAnyTokenKindsFound([T_CLASS, FCT::T_ENUM]);
  50194. }
  50195. public function isRisky(): bool
  50196. {
  50197. return true;
  50198. }
  50199. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  50200. {
  50201. foreach ($this->getMethods($tokens) as $element) {
  50202. $index = $element['method_final_index'];
  50203. if ($element['method_of_enum'] || $element['class_is_final']) {
  50204. $this->clearFinal($tokens, $index);
  50205. continue;
  50206. }
  50207. if (!$element['method_is_private'] || false === $this->configuration['private_methods'] || $element['method_is_constructor']) {
  50208. continue;
  50209. }
  50210. $this->clearFinal($tokens, $index);
  50211. }
  50212. }
  50213. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  50214. {
  50215. return new FixerConfigurationResolver([
  50216. (new FixerOptionBuilder('private_methods', 'Private methods of non-`final` classes must not be declared `final`.'))
  50217. ->setAllowedTypes(['bool'])
  50218. ->setDefault(true)
  50219. ->getOption(),
  50220. ]);
  50221. }
  50222. private function getMethods(Tokens $tokens): \Generator
  50223. {
  50224. $tokensAnalyzer = new TokensAnalyzer($tokens);
  50225. $modifierKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_STATIC];
  50226. $enums = [];
  50227. $classesAreFinal = [];
  50228. foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
  50229. if ('method' !== $element['type']) {
  50230. continue;
  50231. }
  50232. $classIndex = $element['classIndex'];
  50233. if (!\array_key_exists($classIndex, $enums)) {
  50234. $enums[$classIndex] = $tokens[$classIndex]->isGivenKind(FCT::T_ENUM);
  50235. }
  50236. $element['method_final_index'] = null;
  50237. $element['method_is_private'] = false;
  50238. $previous = $index;
  50239. do {
  50240. $previous = $tokens->getPrevMeaningfulToken($previous);
  50241. if ($tokens[$previous]->isGivenKind(T_PRIVATE)) {
  50242. $element['method_is_private'] = true;
  50243. } elseif ($tokens[$previous]->isGivenKind(T_FINAL)) {
  50244. $element['method_final_index'] = $previous;
  50245. }
  50246. } while ($tokens[$previous]->isGivenKind($modifierKinds));
  50247. if ($enums[$classIndex]) {
  50248. $element['method_of_enum'] = true;
  50249. yield $element;
  50250. continue;
  50251. }
  50252. if (!\array_key_exists($classIndex, $classesAreFinal)) {
  50253. $modifiers = $tokensAnalyzer->getClassyModifiers($classIndex);
  50254. $classesAreFinal[$classIndex] = isset($modifiers['final']);
  50255. }
  50256. $element['method_of_enum'] = false;
  50257. $element['class_is_final'] = $classesAreFinal[$classIndex];
  50258. $element['method_is_constructor'] = '__construct' === strtolower($tokens[$tokens->getNextMeaningfulToken($index)]->getContent());
  50259. yield $element;
  50260. }
  50261. }
  50262. private function clearFinal(Tokens $tokens, ?int $index): void
  50263. {
  50264. if (null === $index) {
  50265. return;
  50266. }
  50267. $tokens->clearAt($index);
  50268. ++$index;
  50269. if ($tokens[$index]->isWhitespace()) {
  50270. $tokens->clearAt($index);
  50271. }
  50272. }
  50273. }
  50274. <?php
  50275. declare(strict_types=1);
  50276. namespace PhpCsFixer\Fixer\ClassNotation;
  50277. use PhpCsFixer\AbstractFixer;
  50278. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  50279. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  50280. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  50281. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  50282. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  50283. use PhpCsFixer\FixerDefinition\CodeSample;
  50284. use PhpCsFixer\FixerDefinition\FixerDefinition;
  50285. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  50286. use PhpCsFixer\FixerDefinition\VersionSpecification;
  50287. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  50288. use PhpCsFixer\Preg;
  50289. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  50290. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  50291. use PhpCsFixer\Tokenizer\CT;
  50292. use PhpCsFixer\Tokenizer\FCT;
  50293. use PhpCsFixer\Tokenizer\Token;
  50294. use PhpCsFixer\Tokenizer\Tokens;
  50295. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  50296. /**
  50297. @phpstan-type
  50298. @phpstan-type
  50299. @implements
  50300. */
  50301. final class OrderedTypesFixer extends AbstractFixer implements ConfigurableFixerInterface
  50302. {
  50303. /**
  50304. @use */
  50305. use ConfigurableFixerTrait;
  50306. private const PROPERTY_MODIFIERS = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  50307. public function getDefinition(): FixerDefinitionInterface
  50308. {
  50309. return new FixerDefinition(
  50310. 'Sort union types and intersection types using configured order.',
  50311. [
  50312. new CodeSample(
  50313. '<?php
  50314. try {
  50315. cache()->save($foo);
  50316. } catch (\RuntimeException|CacheException $e) {
  50317. logger($e);
  50318. throw $e;
  50319. }
  50320. '
  50321. ),
  50322. new VersionSpecificCodeSample(
  50323. '<?php
  50324. interface Foo
  50325. {
  50326. public function bar(\Aaa|\AA $foo): string|int;
  50327. }
  50328. ',
  50329. new VersionSpecification(8_00_00),
  50330. [
  50331. 'case_sensitive' => true,
  50332. ]
  50333. ),
  50334. new VersionSpecificCodeSample(
  50335. '<?php
  50336. interface Foo
  50337. {
  50338. public function bar(null|string|int $foo): string|int;
  50339. public function foo(\Stringable&\Countable $obj): int;
  50340. }
  50341. ',
  50342. new VersionSpecification(8_01_00),
  50343. ['null_adjustment' => 'always_last']
  50344. ),
  50345. new VersionSpecificCodeSample(
  50346. '<?php
  50347. interface Bar
  50348. {
  50349. public function bar(null|string|int $foo): string|int;
  50350. }
  50351. ',
  50352. new VersionSpecification(8_00_00),
  50353. [
  50354. 'sort_algorithm' => 'none',
  50355. 'null_adjustment' => 'always_last',
  50356. ]
  50357. ),
  50358. ]
  50359. );
  50360. }
  50361. public function getPriority(): int
  50362. {
  50363. return 0;
  50364. }
  50365. public function isCandidate(Tokens $tokens): bool
  50366. {
  50367. return $tokens->isAnyTokenKindsFound([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION]);
  50368. }
  50369. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  50370. {
  50371. return new FixerConfigurationResolver([
  50372. (new FixerOptionBuilder('sort_algorithm', 'Whether the types should be sorted alphabetically, or not sorted.'))
  50373. ->setAllowedValues(['alpha', 'none'])
  50374. ->setDefault('alpha')
  50375. ->getOption(),
  50376. (new FixerOptionBuilder('null_adjustment', 'Forces the position of `null` (overrides `sort_algorithm`).'))
  50377. ->setAllowedValues(['always_first', 'always_last', 'none'])
  50378. ->setDefault('always_first')
  50379. ->getOption(),
  50380. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  50381. ->setAllowedTypes(['bool'])
  50382. ->setDefault(false)
  50383. ->getOption(),
  50384. ]);
  50385. }
  50386. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  50387. {
  50388. $functionsAnalyzer = new FunctionsAnalyzer();
  50389. foreach ($this->getElements($tokens) as $index => $type) {
  50390. if ('catch' === $type) {
  50391. $this->fixCatchArgumentType($tokens, $index);
  50392. continue;
  50393. }
  50394. if ('property' === $type) {
  50395. $this->fixPropertyType($tokens, $index);
  50396. continue;
  50397. }
  50398. $this->fixMethodArgumentType($functionsAnalyzer, $tokens, $index);
  50399. $this->fixMethodReturnType($functionsAnalyzer, $tokens, $index);
  50400. }
  50401. }
  50402. /**
  50403. @phpstan-return
  50404. */
  50405. private function getElements(Tokens $tokens): array
  50406. {
  50407. $tokensAnalyzer = new TokensAnalyzer($tokens);
  50408. $elements = array_map(
  50409. static fn (array $element): string => $element['type'],
  50410. array_filter(
  50411. $tokensAnalyzer->getClassyElements(),
  50412. static fn (array $element): bool => \in_array($element['type'], ['method', 'property'], true)
  50413. )
  50414. );
  50415. foreach ($tokens as $index => $token) {
  50416. if ($token->isGivenKind(T_CATCH)) {
  50417. $elements[$index] = 'catch';
  50418. continue;
  50419. }
  50420. if (
  50421. $token->isGivenKind(T_FN)
  50422. || ($token->isGivenKind(T_FUNCTION) && !isset($elements[$index]))
  50423. ) {
  50424. $elements[$index] = 'method';
  50425. }
  50426. }
  50427. return $elements;
  50428. }
  50429. private function collectTypeAnalysis(Tokens $tokens, int $startIndex, int $endIndex): ?TypeAnalysis
  50430. {
  50431. $type = '';
  50432. $typeStartIndex = $tokens->getNextMeaningfulToken($startIndex);
  50433. $typeEndIndex = $typeStartIndex;
  50434. for ($i = $typeStartIndex; $i < $endIndex; ++$i) {
  50435. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  50436. continue;
  50437. }
  50438. $type .= $tokens[$i]->getContent();
  50439. $typeEndIndex = $i;
  50440. }
  50441. return '' !== $type ? new TypeAnalysis($type, $typeStartIndex, $typeEndIndex) : null;
  50442. }
  50443. private function fixCatchArgumentType(Tokens $tokens, int $index): void
  50444. {
  50445. $catchStart = $tokens->getNextTokenOfKind($index, ['(']);
  50446. $catchEnd = $tokens->getNextTokenOfKind($catchStart, [')', [T_VARIABLE]]);
  50447. $catchArgumentType = $this->collectTypeAnalysis($tokens, $catchStart, $catchEnd);
  50448. if (null === $catchArgumentType || !$this->isTypeSortable($catchArgumentType)) {
  50449. return;
  50450. }
  50451. $this->sortTypes($catchArgumentType, $tokens);
  50452. }
  50453. private function fixPropertyType(Tokens $tokens, int $index): void
  50454. {
  50455. $propertyIndex = $index;
  50456. do {
  50457. $index = $tokens->getPrevMeaningfulToken($index);
  50458. } while (!$tokens[$index]->isGivenKind(self::PROPERTY_MODIFIERS));
  50459. $propertyType = $this->collectTypeAnalysis($tokens, $index, $propertyIndex);
  50460. if (null === $propertyType || !$this->isTypeSortable($propertyType)) {
  50461. return;
  50462. }
  50463. $this->sortTypes($propertyType, $tokens);
  50464. }
  50465. private function fixMethodArgumentType(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index): void
  50466. {
  50467. foreach ($functionsAnalyzer->getFunctionArguments($tokens, $index) as $argumentInfo) {
  50468. $argumentType = $argumentInfo->getTypeAnalysis();
  50469. if (null === $argumentType || !$this->isTypeSortable($argumentType)) {
  50470. continue;
  50471. }
  50472. $this->sortTypes($argumentType, $tokens);
  50473. }
  50474. }
  50475. private function fixMethodReturnType(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index): void
  50476. {
  50477. $returnType = $functionsAnalyzer->getFunctionReturnType($tokens, $index);
  50478. if (null === $returnType || !$this->isTypeSortable($returnType)) {
  50479. return;
  50480. }
  50481. $this->sortTypes($returnType, $tokens);
  50482. }
  50483. private function sortTypes(TypeAnalysis $typeAnalysis, Tokens $tokens): void
  50484. {
  50485. $type = $typeAnalysis->getName();
  50486. if (str_contains($type, '|') && str_contains($type, '&')) {
  50487. [$originalTypes, $glue] = $this->collectDisjunctiveNormalFormTypes($type);
  50488. } else {
  50489. [$originalTypes, $glue] = $this->collectUnionOrIntersectionTypes($type);
  50490. }
  50491. $sortedTypes = array_map(function ($subType) {
  50492. if (\is_array($subType)) {
  50493. return $this->runTypesThroughSortingAlgorithm($subType);
  50494. }
  50495. return $subType;
  50496. }, $originalTypes);
  50497. $sortedTypes = $this->runTypesThroughSortingAlgorithm($sortedTypes);
  50498. if ($sortedTypes === $originalTypes) {
  50499. return;
  50500. }
  50501. $tokens->overrideRange(
  50502. $typeAnalysis->getStartIndex(),
  50503. $typeAnalysis->getEndIndex(),
  50504. $this->createTypeDeclarationTokens($sortedTypes, $glue)
  50505. );
  50506. }
  50507. private function isTypeSortable(TypeAnalysis $type): bool
  50508. {
  50509. return str_contains($type->getName(), '|') || str_contains($type->getName(), '&');
  50510. }
  50511. private function collectDisjunctiveNormalFormTypes(string $type): array
  50512. {
  50513. $types = array_map(static function (string $subType) {
  50514. if (str_starts_with($subType, '(')) {
  50515. return explode('&', trim($subType, '()'));
  50516. }
  50517. return $subType;
  50518. }, explode('|', $type));
  50519. return [$types, '|'];
  50520. }
  50521. private function collectUnionOrIntersectionTypes(string $type): array
  50522. {
  50523. $types = explode('|', $type);
  50524. $glue = '|';
  50525. if (1 === \count($types)) {
  50526. $types = explode('&', $type);
  50527. $glue = '&';
  50528. }
  50529. return [$types, $glue];
  50530. }
  50531. private function runTypesThroughSortingAlgorithm(array $types): array
  50532. {
  50533. $normalizeType = static fn (string $type): string => Preg::replace('/^\\\?/', '', $type);
  50534. usort($types, function ($a, $b) use ($normalizeType): int {
  50535. if (\is_array($a)) {
  50536. $a = implode('&', $a);
  50537. }
  50538. if (\is_array($b)) {
  50539. $b = implode('&', $b);
  50540. }
  50541. $a = $normalizeType($a);
  50542. $b = $normalizeType($b);
  50543. $lowerCaseA = strtolower($a);
  50544. $lowerCaseB = strtolower($b);
  50545. if ('none' !== $this->configuration['null_adjustment']) {
  50546. if ('null' === $lowerCaseA && 'null' !== $lowerCaseB) {
  50547. return 'always_last' === $this->configuration['null_adjustment'] ? 1 : -1;
  50548. }
  50549. if ('null' !== $lowerCaseA && 'null' === $lowerCaseB) {
  50550. return 'always_last' === $this->configuration['null_adjustment'] ? -1 : 1;
  50551. }
  50552. }
  50553. if ('alpha' === $this->configuration['sort_algorithm']) {
  50554. return true === $this->configuration['case_sensitive'] ? $a <=> $b : strcasecmp($a, $b);
  50555. }
  50556. return 0;
  50557. });
  50558. return $types;
  50559. }
  50560. private function createTypeDeclarationTokens(array $types, string $glue, bool $isDisjunctive = false): array
  50561. {
  50562. static $specialTypes = [
  50563. 'array' => [CT::T_ARRAY_TYPEHINT, 'array'],
  50564. 'callable' => [T_CALLABLE, 'callable'],
  50565. 'static' => [T_STATIC, 'static'],
  50566. ];
  50567. static $glues = [
  50568. '|' => [CT::T_TYPE_ALTERNATION, '|'],
  50569. '&' => [CT::T_TYPE_INTERSECTION, '&'],
  50570. ];
  50571. $count = \count($types);
  50572. $newTokens = [];
  50573. foreach ($types as $i => $type) {
  50574. if (\is_array($type)) {
  50575. $newTokens = [
  50576. ...$newTokens,
  50577. ...$this->createTypeDeclarationTokens($type, '&', true),
  50578. ];
  50579. } elseif (isset($specialTypes[$type])) {
  50580. $newTokens[] = new Token($specialTypes[$type]);
  50581. } else {
  50582. foreach (explode('\\', $type) as $nsIndex => $value) {
  50583. if (0 === $nsIndex && '' === $value) {
  50584. continue;
  50585. }
  50586. if ($nsIndex > 0) {
  50587. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  50588. }
  50589. $newTokens[] = new Token([T_STRING, $value]);
  50590. }
  50591. }
  50592. if ($i <= $count - 2) {
  50593. $newTokens[] = new Token($glues[$glue]);
  50594. }
  50595. }
  50596. if ($isDisjunctive) {
  50597. array_unshift($newTokens, new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, '(']));
  50598. $newTokens[] = new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE, ')']);
  50599. }
  50600. return $newTokens;
  50601. }
  50602. }
  50603. <?php
  50604. declare(strict_types=1);
  50605. namespace PhpCsFixer\Fixer\ClassNotation;
  50606. use PhpCsFixer\AbstractFixer;
  50607. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  50608. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  50609. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  50610. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  50611. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  50612. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  50613. use PhpCsFixer\FixerDefinition\CodeSample;
  50614. use PhpCsFixer\FixerDefinition\FixerDefinition;
  50615. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  50616. use PhpCsFixer\FixerDefinition\VersionSpecification;
  50617. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  50618. use PhpCsFixer\Preg;
  50619. use PhpCsFixer\Tokenizer\CT;
  50620. use PhpCsFixer\Tokenizer\FCT;
  50621. use PhpCsFixer\Tokenizer\Token;
  50622. use PhpCsFixer\Tokenizer\Tokens;
  50623. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  50624. use PhpCsFixer\Utils;
  50625. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  50626. /**
  50627. @phpstan-type
  50628. @phpstan-type
  50629. @phpstan-type
  50630. @phpstan-type
  50631. @implements
  50632. */
  50633. final class ClassAttributesSeparationFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  50634. {
  50635. /**
  50636. @use */
  50637. use ConfigurableFixerTrait;
  50638. public const SPACING_NONE = 'none';
  50639. public const SPACING_ONE = 'one';
  50640. private const SPACING_ONLY_IF_META = 'only_if_meta';
  50641. private const MODIFIER_TYPES = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_ABSTRACT, T_FINAL, T_STATIC, T_STRING, T_NS_SEPARATOR, T_VAR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  50642. private array $classElementTypes = [];
  50643. public function getDefinition(): FixerDefinitionInterface
  50644. {
  50645. return new FixerDefinition(
  50646. 'Class, trait and interface elements must be separated with one or none blank line.',
  50647. [
  50648. new CodeSample(
  50649. '<?php
  50650. final class Sample
  50651. {
  50652. protected function foo()
  50653. {
  50654. }
  50655. protected function bar()
  50656. {
  50657. }
  50658. }
  50659. '
  50660. ),
  50661. new CodeSample(
  50662. '<?php
  50663. class Sample
  50664. {private $a; // foo
  50665. /** second in a hour */
  50666. private $b;
  50667. }
  50668. ',
  50669. ['elements' => ['property' => self::SPACING_ONE]]
  50670. ),
  50671. new CodeSample(
  50672. '<?php
  50673. class Sample
  50674. {
  50675. const A = 1;
  50676. /** seconds in some hours */
  50677. const B = 3600;
  50678. }
  50679. ',
  50680. ['elements' => ['const' => self::SPACING_ONE]]
  50681. ),
  50682. new CodeSample(
  50683. '<?php
  50684. class Sample
  50685. {
  50686. /** @var int */
  50687. const SECOND = 1;
  50688. /** @var int */
  50689. const MINUTE = 60;
  50690. const HOUR = 3600;
  50691. const DAY = 86400;
  50692. }
  50693. ',
  50694. ['elements' => ['const' => self::SPACING_ONLY_IF_META]]
  50695. ),
  50696. new VersionSpecificCodeSample(
  50697. '<?php
  50698. class Sample
  50699. {
  50700. public $a;
  50701. #[SetUp]
  50702. public $b;
  50703. /** @var string */
  50704. public $c;
  50705. /** @internal */
  50706. #[Assert\String()]
  50707. public $d;
  50708. public $e;
  50709. }
  50710. ',
  50711. new VersionSpecification(8_00_00),
  50712. ['elements' => ['property' => self::SPACING_ONLY_IF_META]]
  50713. ),
  50714. ]
  50715. );
  50716. }
  50717. public function getPriority(): int
  50718. {
  50719. return 55;
  50720. }
  50721. public function isCandidate(Tokens $tokens): bool
  50722. {
  50723. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  50724. }
  50725. protected function configurePostNormalisation(): void
  50726. {
  50727. $this->classElementTypes = [];
  50728. foreach ($this->configuration['elements'] as $elementType => $spacing) {
  50729. $this->classElementTypes[$elementType] = $spacing;
  50730. }
  50731. }
  50732. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  50733. {
  50734. foreach ($this->getElementsByClass($tokens) as $class) {
  50735. $elements = $class['elements'];
  50736. $elementCount = \count($elements);
  50737. if (0 === $elementCount) {
  50738. continue;
  50739. }
  50740. if (isset($this->classElementTypes[$elements[0]['type']])) {
  50741. $this->fixSpaceBelowClassElement($tokens, $class);
  50742. $this->fixSpaceAboveClassElement($tokens, $class, 0);
  50743. }
  50744. for ($index = 1; $index < $elementCount; ++$index) {
  50745. if (isset($this->classElementTypes[$elements[$index]['type']])) {
  50746. $this->fixSpaceAboveClassElement($tokens, $class, $index);
  50747. }
  50748. }
  50749. }
  50750. }
  50751. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  50752. {
  50753. return new FixerConfigurationResolver([
  50754. (new FixerOptionBuilder('elements', 'Dictionary of `const|method|property|trait_import|case` => `none|one|only_if_meta` values.'))
  50755. ->setAllowedTypes(['array<string, string>'])
  50756. ->setAllowedValues([static function (array $option): bool {
  50757. foreach ($option as $type => $spacing) {
  50758. $supportedTypes = ['const', 'method', 'property', 'trait_import', 'case'];
  50759. if (!\in_array($type, $supportedTypes, true)) {
  50760. throw new InvalidOptionsException(
  50761. \sprintf(
  50762. 'Unexpected element type, expected any of %s, got "%s".',
  50763. Utils::naturalLanguageJoin($supportedTypes),
  50764. \gettype($type).'#'.$type
  50765. )
  50766. );
  50767. }
  50768. $supportedSpacings = [self::SPACING_NONE, self::SPACING_ONE, self::SPACING_ONLY_IF_META];
  50769. if (!\in_array($spacing, $supportedSpacings, true)) {
  50770. throw new InvalidOptionsException(
  50771. \sprintf(
  50772. 'Unexpected spacing for element type "%s", expected any of %s, got "%s".',
  50773. $spacing,
  50774. Utils::naturalLanguageJoin($supportedSpacings),
  50775. \is_object($spacing) ? \get_class($spacing) : (null === $spacing ? 'null' : \gettype($spacing).'#'.$spacing)
  50776. )
  50777. );
  50778. }
  50779. }
  50780. return true;
  50781. }])
  50782. ->setDefault([
  50783. 'const' => self::SPACING_ONE,
  50784. 'method' => self::SPACING_ONE,
  50785. 'property' => self::SPACING_ONE,
  50786. 'trait_import' => self::SPACING_NONE,
  50787. 'case' => self::SPACING_NONE,
  50788. ])
  50789. ->getOption(),
  50790. ]);
  50791. }
  50792. private function fixSpaceAboveClassElement(Tokens $tokens, array $class, int $elementIndex): void
  50793. {
  50794. $element = $class['elements'][$elementIndex];
  50795. $elementAboveEnd = isset($class['elements'][$elementIndex + 1]) ? $class['elements'][$elementIndex + 1]['end'] : 0;
  50796. $nonWhiteAbove = $tokens->getPrevNonWhitespace($element['start']);
  50797. if ($nonWhiteAbove === $class['open']) {
  50798. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], 1);
  50799. return;
  50800. }
  50801. if ($tokens[$nonWhiteAbove]->isGivenKind(T_COMMENT)) {
  50802. if ($elementAboveEnd === $nonWhiteAbove) {
  50803. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], $this->determineRequiredLineCount($tokens, $class, $elementIndex));
  50804. return;
  50805. }
  50806. if ($tokens[$nonWhiteAbove + 1]->isWhitespace() && substr_count($tokens[$nonWhiteAbove + 1]->getContent(), "\n") > 1) {
  50807. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], 2);
  50808. return;
  50809. }
  50810. if (
  50811. 1 === $element['start'] - $nonWhiteAbove
  50812. || $tokens[$nonWhiteAbove - 1]->isWhitespace() && substr_count($tokens[$nonWhiteAbove - 1]->getContent(), "\n") > 0
  50813. || $tokens[$nonWhiteAbove + 1]->isWhitespace() && substr_count($tokens[$nonWhiteAbove + 1]->getContent(), "\n") > 0
  50814. ) {
  50815. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], 1);
  50816. $nonWhiteAbove = $this->findCommentBlockStart($tokens, $nonWhiteAbove, $elementAboveEnd);
  50817. $nonWhiteAboveComment = $tokens->getPrevNonWhitespace($nonWhiteAbove);
  50818. if ($nonWhiteAboveComment === $class['open']) {
  50819. if ($tokens[$nonWhiteAboveComment - 1]->isWhitespace() && substr_count($tokens[$nonWhiteAboveComment - 1]->getContent(), "\n") > 0) {
  50820. $this->correctLineBreaks($tokens, $nonWhiteAboveComment, $nonWhiteAbove, 1);
  50821. }
  50822. } else {
  50823. $this->correctLineBreaks($tokens, $nonWhiteAboveComment, $nonWhiteAbove, 2);
  50824. }
  50825. } else {
  50826. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], 2);
  50827. }
  50828. return;
  50829. }
  50830. if ($tokens[$nonWhiteAbove]->isGivenKind([T_DOC_COMMENT, CT::T_ATTRIBUTE_CLOSE])) {
  50831. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], 1);
  50832. $nonWhiteAbove = $this->findCommentBlockStart($tokens, $nonWhiteAbove, $elementAboveEnd);
  50833. $nonWhiteAboveComment = $tokens->getPrevNonWhitespace($nonWhiteAbove);
  50834. $this->correctLineBreaks($tokens, $nonWhiteAboveComment, $nonWhiteAbove, $nonWhiteAboveComment === $class['open'] ? 1 : 2);
  50835. return;
  50836. }
  50837. $this->correctLineBreaks($tokens, $nonWhiteAbove, $element['start'], $this->determineRequiredLineCount($tokens, $class, $elementIndex));
  50838. }
  50839. private function determineRequiredLineCount(Tokens $tokens, array $class, int $elementIndex): int
  50840. {
  50841. $type = $class['elements'][$elementIndex]['type'];
  50842. $spacing = $this->classElementTypes[$type];
  50843. if (self::SPACING_ONE === $spacing) {
  50844. return 2;
  50845. }
  50846. if (self::SPACING_NONE === $spacing) {
  50847. if (!isset($class['elements'][$elementIndex + 1])) {
  50848. return 1;
  50849. }
  50850. $aboveElement = $class['elements'][$elementIndex + 1];
  50851. if ($aboveElement['type'] !== $type) {
  50852. return 2;
  50853. }
  50854. $aboveElementDocCandidateIndex = $tokens->getPrevNonWhitespace($aboveElement['start']);
  50855. return $tokens[$aboveElementDocCandidateIndex]->isGivenKind([T_DOC_COMMENT, CT::T_ATTRIBUTE_CLOSE]) ? 2 : 1;
  50856. }
  50857. if (self::SPACING_ONLY_IF_META === $spacing) {
  50858. $aboveElementDocCandidateIndex = $tokens->getPrevNonWhitespace($class['elements'][$elementIndex]['start']);
  50859. return $tokens[$aboveElementDocCandidateIndex]->isGivenKind([T_DOC_COMMENT, CT::T_ATTRIBUTE_CLOSE]) ? 2 : 1;
  50860. }
  50861. throw new \RuntimeException(\sprintf('Unknown spacing "%s".', $spacing));
  50862. }
  50863. private function fixSpaceBelowClassElement(Tokens $tokens, array $class): void
  50864. {
  50865. $element = $class['elements'][0];
  50866. if ($class['close'] === $tokens->getNextNonWhitespace($element['end'])) {
  50867. $this->correctLineBreaks($tokens, $element['end'], $class['close'], 1);
  50868. }
  50869. }
  50870. private function correctLineBreaks(Tokens $tokens, int $startIndex, int $endIndex, int $reqLineCount): void
  50871. {
  50872. $lineEnding = $this->whitespacesConfig->getLineEnding();
  50873. ++$startIndex;
  50874. $numbOfWhiteTokens = $endIndex - $startIndex;
  50875. if (0 === $numbOfWhiteTokens) {
  50876. $tokens->insertAt($startIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $reqLineCount)]));
  50877. return;
  50878. }
  50879. $lineBreakCount = $this->getLineBreakCount($tokens, $startIndex, $endIndex);
  50880. if ($reqLineCount === $lineBreakCount) {
  50881. return;
  50882. }
  50883. if ($lineBreakCount < $reqLineCount) {
  50884. $tokens[$startIndex] = new Token([
  50885. T_WHITESPACE,
  50886. str_repeat($lineEnding, $reqLineCount - $lineBreakCount).$tokens[$startIndex]->getContent(),
  50887. ]);
  50888. return;
  50889. }
  50890. if (1 === $numbOfWhiteTokens) {
  50891. $tokens[$startIndex] = new Token([
  50892. T_WHITESPACE,
  50893. Preg::replace('/\r\n|\n/', '', $tokens[$startIndex]->getContent(), $lineBreakCount - $reqLineCount),
  50894. ]);
  50895. return;
  50896. }
  50897. $toReplaceCount = $lineBreakCount - $reqLineCount;
  50898. for ($i = $startIndex; $i < $endIndex && $toReplaceCount > 0; ++$i) {
  50899. $tokenLineCount = substr_count($tokens[$i]->getContent(), "\n");
  50900. if ($tokenLineCount > 0) {
  50901. $tokens[$i] = new Token([
  50902. T_WHITESPACE,
  50903. Preg::replace('/\r\n|\n/', '', $tokens[$i]->getContent(), min($toReplaceCount, $tokenLineCount)),
  50904. ]);
  50905. $toReplaceCount -= $tokenLineCount;
  50906. }
  50907. }
  50908. }
  50909. private function getLineBreakCount(Tokens $tokens, int $startIndex, int $endIndex): int
  50910. {
  50911. $lineCount = 0;
  50912. for ($i = $startIndex; $i < $endIndex; ++$i) {
  50913. $lineCount += substr_count($tokens[$i]->getContent(), "\n");
  50914. }
  50915. return $lineCount;
  50916. }
  50917. private function findCommentBlockStart(Tokens $tokens, int $start, int $elementAboveEnd): int
  50918. {
  50919. for ($i = $start; $i > $elementAboveEnd; --$i) {
  50920. if ($tokens[$i]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  50921. $start = $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $i);
  50922. continue;
  50923. }
  50924. if ($tokens[$i]->isComment()) {
  50925. $start = $i;
  50926. continue;
  50927. }
  50928. if (!$tokens[$i]->isWhitespace() || $this->getLineBreakCount($tokens, $i, $i + 1) > 1) {
  50929. break;
  50930. }
  50931. }
  50932. return $start;
  50933. }
  50934. private function getElementsByClass(Tokens $tokens): \Generator
  50935. {
  50936. $tokensAnalyzer = new TokensAnalyzer($tokens);
  50937. $class = $classIndex = false;
  50938. foreach (array_reverse($tokensAnalyzer->getClassyElements(), true) as $index => $element) {
  50939. $element['index'] = $index;
  50940. if ($element['classIndex'] !== $classIndex) {
  50941. if (false !== $class) {
  50942. yield $class;
  50943. }
  50944. $classIndex = $element['classIndex'];
  50945. $classOpen = $tokens->getNextTokenOfKind($classIndex, ['{']);
  50946. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  50947. $class = [
  50948. 'index' => $classIndex,
  50949. 'open' => $classOpen,
  50950. 'close' => $classEnd,
  50951. 'elements' => [],
  50952. ];
  50953. }
  50954. unset($element['classIndex']);
  50955. $element['start'] = $this->getFirstTokenIndexOfClassElement($tokens, $class, $element);
  50956. $element['end'] = $this->getLastTokenIndexOfClassElement($tokens, $class, $element, $tokensAnalyzer);
  50957. $class['elements'][] = $element;
  50958. }
  50959. if (false !== $class) {
  50960. yield $class;
  50961. }
  50962. }
  50963. private function getFirstTokenIndexOfClassElement(Tokens $tokens, array $class, array $element): int
  50964. {
  50965. $firstElementAttributeIndex = $element['index'];
  50966. do {
  50967. $nonWhiteAbove = $tokens->getPrevMeaningfulToken($firstElementAttributeIndex);
  50968. if (null !== $nonWhiteAbove && $tokens[$nonWhiteAbove]->isGivenKind(self::MODIFIER_TYPES)) {
  50969. $firstElementAttributeIndex = $nonWhiteAbove;
  50970. } else {
  50971. break;
  50972. }
  50973. } while ($firstElementAttributeIndex > $class['open']);
  50974. return $firstElementAttributeIndex;
  50975. }
  50976. private function getLastTokenIndexOfClassElement(Tokens $tokens, array $class, array $element, TokensAnalyzer $tokensAnalyzer): int
  50977. {
  50978. if ('method' === $element['type'] && !$tokens[$class['index']]->isGivenKind(T_INTERFACE)) {
  50979. $attributes = $tokensAnalyzer->getMethodAttributes($element['index']);
  50980. if (true === $attributes['abstract']) {
  50981. $elementEndIndex = $tokens->getNextTokenOfKind($element['index'], [';']);
  50982. } else {
  50983. $elementEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $tokens->getNextTokenOfKind($element['index'], ['{']));
  50984. }
  50985. } elseif ('trait_import' === $element['type']) {
  50986. $elementEndIndex = $element['index'];
  50987. do {
  50988. $elementEndIndex = $tokens->getNextMeaningfulToken($elementEndIndex);
  50989. } while ($tokens[$elementEndIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR]) || $tokens[$elementEndIndex]->equals(','));
  50990. if (!$tokens[$elementEndIndex]->equals(';')) {
  50991. $elementEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $tokens->getNextTokenOfKind($element['index'], ['{']));
  50992. }
  50993. } else {
  50994. $elementEndIndex = $tokens->getNextTokenOfKind($element['index'], [';', '{']);
  50995. }
  50996. $singleLineElement = true;
  50997. for ($i = $element['index'] + 1; $i < $elementEndIndex; ++$i) {
  50998. if (str_contains($tokens[$i]->getContent(), "\n")) {
  50999. $singleLineElement = false;
  51000. break;
  51001. }
  51002. }
  51003. if ($singleLineElement) {
  51004. while (true) {
  51005. $nextToken = $tokens[$elementEndIndex + 1];
  51006. if (($nextToken->isComment() || $nextToken->isWhitespace()) && !str_contains($nextToken->getContent(), "\n")) {
  51007. ++$elementEndIndex;
  51008. } else {
  51009. break;
  51010. }
  51011. }
  51012. if ($tokens[$elementEndIndex]->isWhitespace()) {
  51013. $elementEndIndex = $tokens->getPrevNonWhitespace($elementEndIndex);
  51014. }
  51015. }
  51016. return $elementEndIndex;
  51017. }
  51018. }
  51019. <?php
  51020. declare(strict_types=1);
  51021. namespace PhpCsFixer\Fixer\ClassNotation;
  51022. use PhpCsFixer\AbstractFixer;
  51023. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  51024. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  51025. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  51026. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  51027. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  51028. use PhpCsFixer\FixerDefinition\CodeSample;
  51029. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51030. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51031. use PhpCsFixer\Tokenizer\CT;
  51032. use PhpCsFixer\Tokenizer\Tokens;
  51033. /**
  51034. @phpstan-type
  51035. @phpstan-type
  51036. @implements
  51037. */
  51038. final class OrderedTraitsFixer extends AbstractFixer implements ConfigurableFixerInterface
  51039. {
  51040. /**
  51041. @use */
  51042. use ConfigurableFixerTrait;
  51043. public function getDefinition(): FixerDefinitionInterface
  51044. {
  51045. return new FixerDefinition(
  51046. 'Trait `use` statements must be sorted alphabetically.',
  51047. [
  51048. new CodeSample("<?php class Foo { \nuse Z; use A; }\n"),
  51049. new CodeSample(
  51050. "<?php class Foo { \nuse Aaa; use AA; }\n",
  51051. [
  51052. 'case_sensitive' => true,
  51053. ]
  51054. ),
  51055. ],
  51056. null,
  51057. 'Risky when depending on order of the imports.'
  51058. );
  51059. }
  51060. public function isCandidate(Tokens $tokens): bool
  51061. {
  51062. return $tokens->isTokenKindFound(CT::T_USE_TRAIT);
  51063. }
  51064. public function isRisky(): bool
  51065. {
  51066. return true;
  51067. }
  51068. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  51069. {
  51070. return new FixerConfigurationResolver([
  51071. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  51072. ->setAllowedTypes(['bool'])
  51073. ->setDefault(false)
  51074. ->getOption(),
  51075. ]);
  51076. }
  51077. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51078. {
  51079. foreach ($this->findUseStatementsGroups($tokens) as $uses) {
  51080. $this->sortUseStatements($tokens, $uses);
  51081. }
  51082. }
  51083. private function findUseStatementsGroups(Tokens $tokens): iterable
  51084. {
  51085. $uses = [];
  51086. for ($index = 1, $max = \count($tokens); $index < $max; ++$index) {
  51087. $token = $tokens[$index];
  51088. if ($token->isWhitespace() || $token->isComment()) {
  51089. continue;
  51090. }
  51091. if (!$token->isGivenKind(CT::T_USE_TRAIT)) {
  51092. if (\count($uses) > 0) {
  51093. yield $uses;
  51094. $uses = [];
  51095. }
  51096. continue;
  51097. }
  51098. $startIndex = $tokens->getNextNonWhitespace($tokens->getPrevMeaningfulToken($index));
  51099. $endIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  51100. if ($tokens[$endIndex]->equals('{')) {
  51101. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $endIndex);
  51102. }
  51103. $use = [];
  51104. for ($i = $startIndex; $i <= $endIndex; ++$i) {
  51105. $use[] = $tokens[$i];
  51106. }
  51107. $uses[$startIndex] = Tokens::fromArray($use);
  51108. $index = $endIndex;
  51109. }
  51110. }
  51111. private function sortUseStatements(Tokens $tokens, array $uses): void
  51112. {
  51113. foreach ($uses as $use) {
  51114. $this->sortMultipleTraitsInStatement($use);
  51115. }
  51116. $this->sort($tokens, $uses);
  51117. }
  51118. private function sortMultipleTraitsInStatement(Tokens $use): void
  51119. {
  51120. $traits = [];
  51121. $indexOfName = null;
  51122. $name = [];
  51123. for ($index = 0, $max = \count($use); $index < $max; ++$index) {
  51124. $token = $use[$index];
  51125. if ($token->isGivenKind([T_STRING, T_NS_SEPARATOR])) {
  51126. $name[] = $token;
  51127. if (null === $indexOfName) {
  51128. $indexOfName = $index;
  51129. }
  51130. continue;
  51131. }
  51132. if ($token->equalsAny([',', ';', '{'])) {
  51133. $traits[$indexOfName] = Tokens::fromArray($name);
  51134. $name = [];
  51135. $indexOfName = null;
  51136. }
  51137. if ($token->equals('{')) {
  51138. $index = $use->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  51139. }
  51140. }
  51141. $this->sort($use, $traits);
  51142. }
  51143. private function sort(Tokens $tokens, array $elements): void
  51144. {
  51145. $toTraitName = static function (Tokens $use): string {
  51146. $string = '';
  51147. foreach ($use as $token) {
  51148. if ($token->equalsAny([';', '{'])) {
  51149. break;
  51150. }
  51151. if ($token->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  51152. $string .= $token->getContent();
  51153. }
  51154. }
  51155. return ltrim($string, '\\');
  51156. };
  51157. $sortedElements = $elements;
  51158. uasort(
  51159. $sortedElements,
  51160. fn (Tokens $useA, Tokens $useB): int => true === $this->configuration['case_sensitive']
  51161. ? $toTraitName($useA) <=> $toTraitName($useB)
  51162. : strcasecmp($toTraitName($useA), $toTraitName($useB))
  51163. );
  51164. $sortedElements = array_combine(
  51165. array_keys($elements),
  51166. array_values($sortedElements)
  51167. );
  51168. $beforeOverrideCount = $tokens->count();
  51169. foreach (array_reverse($sortedElements, true) as $index => $tokensToInsert) {
  51170. $tokens->overrideRange(
  51171. $index,
  51172. $index + \count($elements[$index]) - 1,
  51173. $tokensToInsert
  51174. );
  51175. }
  51176. if ($beforeOverrideCount < $tokens->count()) {
  51177. $tokens->clearEmptyTokens();
  51178. }
  51179. }
  51180. }
  51181. <?php
  51182. declare(strict_types=1);
  51183. namespace PhpCsFixer\Fixer\ClassNotation;
  51184. use PhpCsFixer\AbstractFixer;
  51185. use PhpCsFixer\FixerDefinition\CodeSample;
  51186. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51187. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51188. use PhpCsFixer\Preg;
  51189. use PhpCsFixer\Tokenizer\CT;
  51190. use PhpCsFixer\Tokenizer\Token;
  51191. use PhpCsFixer\Tokenizer\Tokens;
  51192. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  51193. final class SelfAccessorFixer extends AbstractFixer
  51194. {
  51195. public function getDefinition(): FixerDefinitionInterface
  51196. {
  51197. return new FixerDefinition(
  51198. 'Inside class or interface element `self` should be preferred to the class name itself.',
  51199. [
  51200. new CodeSample(
  51201. '<?php
  51202. class Sample
  51203. {
  51204. const BAZ = 1;
  51205. const BAR = Sample::BAZ;
  51206. public function getBar()
  51207. {
  51208. return Sample::BAR;
  51209. }
  51210. }
  51211. '
  51212. ),
  51213. ],
  51214. null,
  51215. 'Risky when using dynamic calls like get_called_class() or late static binding.'
  51216. );
  51217. }
  51218. public function isCandidate(Tokens $tokens): bool
  51219. {
  51220. return $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
  51221. }
  51222. public function getPriority(): int
  51223. {
  51224. return -11;
  51225. }
  51226. public function isRisky(): bool
  51227. {
  51228. return true;
  51229. }
  51230. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51231. {
  51232. $tokensAnalyzer = new TokensAnalyzer($tokens);
  51233. foreach ($tokens->getNamespaceDeclarations() as $namespace) {
  51234. for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
  51235. if (!$tokens[$index]->isGivenKind([T_CLASS, T_INTERFACE]) || $tokensAnalyzer->isAnonymousClass($index)) {
  51236. continue;
  51237. }
  51238. $nameIndex = $tokens->getNextTokenOfKind($index, [[T_STRING]]);
  51239. $startIndex = $tokens->getNextTokenOfKind($nameIndex, ['{']);
  51240. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  51241. $name = $tokens[$nameIndex]->getContent();
  51242. $this->replaceNameOccurrences($tokens, $namespace->getFullName(), $name, $startIndex, $endIndex);
  51243. $index = $endIndex;
  51244. }
  51245. }
  51246. }
  51247. private function replaceNameOccurrences(Tokens $tokens, string $namespace, string $name, int $startIndex, int $endIndex): void
  51248. {
  51249. $tokensAnalyzer = new TokensAnalyzer($tokens);
  51250. $insideMethodSignatureUntil = null;
  51251. for ($i = $startIndex; $i < $endIndex; ++$i) {
  51252. if ($i === $insideMethodSignatureUntil) {
  51253. $insideMethodSignatureUntil = null;
  51254. }
  51255. $token = $tokens[$i];
  51256. if ($token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($i)) {
  51257. $i = $tokens->getNextTokenOfKind($i, ['{']);
  51258. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  51259. continue;
  51260. }
  51261. if ($token->isGivenKind(T_FN)) {
  51262. $i = $tokensAnalyzer->getLastTokenIndexOfArrowFunction($i);
  51263. $i = $tokens->getNextMeaningfulToken($i);
  51264. continue;
  51265. }
  51266. if ($token->isGivenKind(T_FUNCTION)) {
  51267. if ($tokensAnalyzer->isLambda($i)) {
  51268. $i = $tokens->getNextTokenOfKind($i, ['{']);
  51269. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  51270. continue;
  51271. }
  51272. $i = $tokens->getNextTokenOfKind($i, ['(']);
  51273. $insideMethodSignatureUntil = $tokens->getNextTokenOfKind($i, ['{', ';']);
  51274. continue;
  51275. }
  51276. if (!$token->equals([T_STRING, $name], false)) {
  51277. continue;
  51278. }
  51279. $nextToken = $tokens[$tokens->getNextMeaningfulToken($i)];
  51280. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  51281. continue;
  51282. }
  51283. $classStartIndex = $i;
  51284. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($i)];
  51285. if ($prevToken->isGivenKind(T_NS_SEPARATOR)) {
  51286. $classStartIndex = $this->getClassStart($tokens, $i, $namespace);
  51287. if (null === $classStartIndex) {
  51288. continue;
  51289. }
  51290. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($classStartIndex)];
  51291. }
  51292. if ($prevToken->isGivenKind(T_STRING) || $prevToken->isObjectOperator()) {
  51293. continue;
  51294. }
  51295. if (
  51296. $prevToken->isGivenKind([T_INSTANCEOF, T_NEW])
  51297. || $nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)
  51298. || (
  51299. null !== $insideMethodSignatureUntil
  51300. && $i < $insideMethodSignatureUntil
  51301. && $prevToken->equalsAny(['(', ',', [CT::T_NULLABLE_TYPE], [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_COLON]])
  51302. )
  51303. ) {
  51304. for ($j = $classStartIndex; $j < $i; ++$j) {
  51305. $tokens->clearTokenAndMergeSurroundingWhitespace($j);
  51306. }
  51307. $tokens[$i] = new Token([T_STRING, 'self']);
  51308. }
  51309. }
  51310. }
  51311. private function getClassStart(Tokens $tokens, int $index, string $namespace): ?int
  51312. {
  51313. $namespace = ('' !== $namespace ? '\\'.$namespace : '').'\\';
  51314. foreach (array_reverse(Preg::split('/(\\\)/', $namespace, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)) as $piece) {
  51315. $index = $tokens->getPrevMeaningfulToken($index);
  51316. if ('\\' === $piece) {
  51317. if (!$tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  51318. return null;
  51319. }
  51320. } elseif (!$tokens[$index]->equals([T_STRING, $piece], false)) {
  51321. return null;
  51322. }
  51323. }
  51324. return $index;
  51325. }
  51326. }
  51327. <?php
  51328. declare(strict_types=1);
  51329. namespace PhpCsFixer\Fixer\ClassNotation;
  51330. use PhpCsFixer\AbstractFixer;
  51331. use PhpCsFixer\FixerDefinition\CodeSample;
  51332. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51333. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51334. use PhpCsFixer\Tokenizer\Token;
  51335. use PhpCsFixer\Tokenizer\Tokens;
  51336. final class FinalPublicMethodForAbstractClassFixer extends AbstractFixer
  51337. {
  51338. private array $magicMethods = [
  51339. '__construct' => true,
  51340. '__destruct' => true,
  51341. '__call' => true,
  51342. '__callstatic' => true,
  51343. '__get' => true,
  51344. '__set' => true,
  51345. '__isset' => true,
  51346. '__unset' => true,
  51347. '__sleep' => true,
  51348. '__wakeup' => true,
  51349. '__tostring' => true,
  51350. '__invoke' => true,
  51351. '__set_state' => true,
  51352. '__clone' => true,
  51353. '__debuginfo' => true,
  51354. ];
  51355. public function getDefinition(): FixerDefinitionInterface
  51356. {
  51357. return new FixerDefinition(
  51358. 'All `public` methods of `abstract` classes should be `final`.',
  51359. [
  51360. new CodeSample(
  51361. '<?php
  51362. abstract class AbstractMachine
  51363. {
  51364. public function start()
  51365. {}
  51366. }
  51367. '
  51368. ),
  51369. ],
  51370. 'Enforce API encapsulation in an inheritance architecture. '
  51371. .'If you want to override a method, use the Template method pattern.',
  51372. 'Risky when overriding `public` methods of `abstract` classes.'
  51373. );
  51374. }
  51375. public function isCandidate(Tokens $tokens): bool
  51376. {
  51377. return $tokens->isAllTokenKindsFound([T_ABSTRACT, T_PUBLIC, T_FUNCTION]);
  51378. }
  51379. public function isRisky(): bool
  51380. {
  51381. return true;
  51382. }
  51383. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51384. {
  51385. $abstracts = array_keys($tokens->findGivenKind(T_ABSTRACT));
  51386. foreach (array_reverse($abstracts) as $abstractIndex) {
  51387. $classIndex = $tokens->getNextTokenOfKind($abstractIndex, [[T_CLASS], [T_FUNCTION]]);
  51388. if (!$tokens[$classIndex]->isGivenKind(T_CLASS)) {
  51389. continue;
  51390. }
  51391. $classOpen = $tokens->getNextTokenOfKind($classIndex, ['{']);
  51392. $classClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  51393. $this->fixClass($tokens, $classOpen, $classClose);
  51394. }
  51395. }
  51396. private function fixClass(Tokens $tokens, int $classOpenIndex, int $classCloseIndex): void
  51397. {
  51398. for ($index = $classCloseIndex - 1; $index > $classOpenIndex; --$index) {
  51399. if ($tokens[$index]->equals('}')) {
  51400. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  51401. continue;
  51402. }
  51403. if (!$tokens[$index]->isGivenKind(T_PUBLIC)) {
  51404. continue;
  51405. }
  51406. $nextIndex = $tokens->getNextMeaningfulToken($index);
  51407. $nextToken = $tokens[$nextIndex];
  51408. if ($nextToken->isGivenKind(T_STATIC)) {
  51409. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  51410. $nextToken = $tokens[$nextIndex];
  51411. }
  51412. if (!$nextToken->isGivenKind(T_FUNCTION)) {
  51413. continue;
  51414. }
  51415. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  51416. $nextToken = $tokens[$nextIndex];
  51417. if (isset($this->magicMethods[strtolower($nextToken->getContent())])) {
  51418. continue;
  51419. }
  51420. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  51421. $prevToken = $tokens[$prevIndex];
  51422. if ($prevToken->isGivenKind(T_STATIC)) {
  51423. $index = $prevIndex;
  51424. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  51425. $prevToken = $tokens[$prevIndex];
  51426. }
  51427. if ($prevToken->isGivenKind([T_ABSTRACT, T_FINAL])) {
  51428. $index = $prevIndex;
  51429. continue;
  51430. }
  51431. $tokens->insertAt(
  51432. $index,
  51433. [
  51434. new Token([T_FINAL, 'final']),
  51435. new Token([T_WHITESPACE, ' ']),
  51436. ]
  51437. );
  51438. }
  51439. }
  51440. }
  51441. <?php
  51442. declare(strict_types=1);
  51443. namespace PhpCsFixer\Fixer\ClassNotation;
  51444. use PhpCsFixer\AbstractFixer;
  51445. use PhpCsFixer\FixerDefinition\CodeSample;
  51446. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51447. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51448. use PhpCsFixer\FixerDefinition\VersionSpecification;
  51449. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  51450. use PhpCsFixer\Tokenizer\FCT;
  51451. use PhpCsFixer\Tokenizer\Token;
  51452. use PhpCsFixer\Tokenizer\Tokens;
  51453. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  51454. final class SelfStaticAccessorFixer extends AbstractFixer
  51455. {
  51456. private const CLASSY_TYPES = [T_CLASS, FCT::T_ENUM];
  51457. private const CLASSY_TOKENS_OF_INTEREST = [[T_CLASS], [FCT::T_ENUM]];
  51458. private TokensAnalyzer $tokensAnalyzer;
  51459. public function getDefinition(): FixerDefinitionInterface
  51460. {
  51461. return new FixerDefinition(
  51462. 'Inside an enum or `final`/anonymous class, `self` should be preferred over `static`.',
  51463. [
  51464. new CodeSample(
  51465. '<?php
  51466. final class Sample
  51467. {
  51468. private static $A = 1;
  51469. public function getBar()
  51470. {
  51471. return static::class.static::test().static::$A;
  51472. }
  51473. private static function test()
  51474. {
  51475. return \'test\';
  51476. }
  51477. }
  51478. '
  51479. ),
  51480. new CodeSample(
  51481. '<?php
  51482. final class Foo
  51483. {
  51484. public function bar()
  51485. {
  51486. return new static();
  51487. }
  51488. }
  51489. '
  51490. ),
  51491. new CodeSample(
  51492. '<?php
  51493. final class Foo
  51494. {
  51495. public function isBar()
  51496. {
  51497. return $foo instanceof static;
  51498. }
  51499. }
  51500. '
  51501. ),
  51502. new CodeSample(
  51503. '<?php
  51504. $a = new class() {
  51505. public function getBar()
  51506. {
  51507. return static::class;
  51508. }
  51509. };
  51510. '
  51511. ),
  51512. new VersionSpecificCodeSample(
  51513. '<?php
  51514. enum Foo
  51515. {
  51516. public const A = 123;
  51517. public static function bar(): void
  51518. {
  51519. echo static::A;
  51520. }
  51521. }
  51522. ',
  51523. new VersionSpecification(8_01_00)
  51524. ),
  51525. ]
  51526. );
  51527. }
  51528. public function isCandidate(Tokens $tokens): bool
  51529. {
  51530. return $tokens->isTokenKindFound(T_STATIC)
  51531. && $tokens->isAnyTokenKindsFound(self::CLASSY_TYPES)
  51532. && $tokens->isAnyTokenKindsFound([T_DOUBLE_COLON, T_NEW, T_INSTANCEOF]);
  51533. }
  51534. public function getPriority(): int
  51535. {
  51536. return -10;
  51537. }
  51538. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51539. {
  51540. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  51541. $classyIndex = $tokens->getNextTokenOfKind(0, self::CLASSY_TOKENS_OF_INTEREST);
  51542. while (null !== $classyIndex) {
  51543. if ($tokens[$classyIndex]->isGivenKind(T_CLASS)) {
  51544. $modifiers = $this->tokensAnalyzer->getClassyModifiers($classyIndex);
  51545. if (
  51546. isset($modifiers['final'])
  51547. || $this->tokensAnalyzer->isAnonymousClass($classyIndex)
  51548. ) {
  51549. $classyIndex = $this->fixClassy($tokens, $classyIndex);
  51550. }
  51551. } else {
  51552. $classyIndex = $this->fixClassy($tokens, $classyIndex);
  51553. }
  51554. $classyIndex = $tokens->getNextTokenOfKind($classyIndex, self::CLASSY_TOKENS_OF_INTEREST);
  51555. }
  51556. }
  51557. private function fixClassy(Tokens $tokens, int $index): int
  51558. {
  51559. $index = $tokens->getNextTokenOfKind($index, ['{']);
  51560. $classOpenCount = 1;
  51561. while ($classOpenCount > 0) {
  51562. ++$index;
  51563. if ($tokens[$index]->equals('{')) {
  51564. ++$classOpenCount;
  51565. continue;
  51566. }
  51567. if ($tokens[$index]->equals('}')) {
  51568. --$classOpenCount;
  51569. continue;
  51570. }
  51571. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  51572. if ($this->tokensAnalyzer->isLambda($index)) {
  51573. $index = $tokens->getNextTokenOfKind($index, ['{']);
  51574. $openCount = 1;
  51575. do {
  51576. $index = $tokens->getNextTokenOfKind($index, ['}', '{', [T_CLASS]]);
  51577. if ($tokens[$index]->equals('}')) {
  51578. --$openCount;
  51579. } elseif ($tokens[$index]->equals('{')) {
  51580. ++$openCount;
  51581. } else {
  51582. $index = $this->fixClassy($tokens, $index);
  51583. }
  51584. } while ($openCount > 0);
  51585. }
  51586. continue;
  51587. }
  51588. if ($tokens[$index]->isGivenKind([T_NEW, T_INSTANCEOF])) {
  51589. $index = $tokens->getNextMeaningfulToken($index);
  51590. if ($tokens[$index]->isGivenKind(T_STATIC)) {
  51591. $tokens[$index] = new Token([T_STRING, 'self']);
  51592. }
  51593. continue;
  51594. }
  51595. if (!$tokens[$index]->isGivenKind(T_STATIC)) {
  51596. continue;
  51597. }
  51598. $staticIndex = $index;
  51599. $index = $tokens->getNextMeaningfulToken($index);
  51600. if (!$tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  51601. continue;
  51602. }
  51603. $tokens[$staticIndex] = new Token([T_STRING, 'self']);
  51604. }
  51605. return $index;
  51606. }
  51607. }
  51608. <?php
  51609. declare(strict_types=1);
  51610. namespace PhpCsFixer\Fixer\ClassNotation;
  51611. use PhpCsFixer\AbstractFixer;
  51612. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  51613. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  51614. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  51615. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  51616. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  51617. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  51618. use PhpCsFixer\FixerDefinition\CodeSample;
  51619. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51620. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51621. use PhpCsFixer\FixerDefinition\VersionSpecification;
  51622. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  51623. use PhpCsFixer\Tokenizer\CT;
  51624. use PhpCsFixer\Tokenizer\FCT;
  51625. use PhpCsFixer\Tokenizer\Token;
  51626. use PhpCsFixer\Tokenizer\Tokens;
  51627. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  51628. /**
  51629. @phpstan-type
  51630. @phpstan-type
  51631. @implements
  51632. */
  51633. final class VisibilityRequiredFixer extends AbstractFixer implements ConfigurableFixerInterface
  51634. {
  51635. /**
  51636. @use */
  51637. use ConfigurableFixerTrait;
  51638. private const PROPERTY_TYPE_DECLARATION_KINDS = [T_STRING, T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE];
  51639. private const EXPECTED_KINDS_GENERIC = [T_ABSTRACT, T_FINAL, T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  51640. private const EXPECTED_KINDS_PROPERTY_KINDS = [...self::EXPECTED_KINDS_GENERIC, ...self::PROPERTY_TYPE_DECLARATION_KINDS];
  51641. private array $elements = ['const', 'method', 'property'];
  51642. public function getDefinition(): FixerDefinitionInterface
  51643. {
  51644. return new FixerDefinition(
  51645. 'Classes, constants, properties, and methods MUST have visibility declared, and keyword modifiers MUST be in the following order:'
  51646. .' inheritance modifier (`abstract` or `final`),'
  51647. .' visibility modifier (`public`, `protected`, or `private`),'
  51648. .' set-visibility modifier (`public(set)`, `protected(set)`, or `private(set)`),'
  51649. .' scope modifier (`static`),'
  51650. .' mutation modifier (`readonly`),'
  51651. .' type declaration, name.',
  51652. [
  51653. new CodeSample(
  51654. '<?php
  51655. abstract class ClassName
  51656. {
  51657. const SAMPLE = 1;
  51658. var $a;
  51659. protected string $foo;
  51660. static protected int $beep;
  51661. static public final function bar() {}
  51662. protected abstract function zim();
  51663. function zex() {}
  51664. }
  51665. ',
  51666. ),
  51667. new VersionSpecificCodeSample(
  51668. '<?php
  51669. abstract class ClassName
  51670. {
  51671. const SAMPLE = 1;
  51672. var $a;
  51673. readonly protected string $foo;
  51674. static protected int $beep;
  51675. static public final function bar() {}
  51676. protected abstract function zim();
  51677. function zex() {}
  51678. }
  51679. readonly final class ValueObject
  51680. {
  51681. // ...
  51682. }
  51683. ',
  51684. new VersionSpecification(8_02_00)
  51685. ),
  51686. new VersionSpecificCodeSample(
  51687. '<?php
  51688. abstract class ClassName
  51689. {
  51690. const SAMPLE = 1;
  51691. var $a;
  51692. protected abstract string $bar { get => "a"; set; }
  51693. readonly final protected string $foo;
  51694. static protected final int $beep;
  51695. static public final function bar() {}
  51696. protected abstract function zim();
  51697. function zex() {}
  51698. }
  51699. readonly final class ValueObject
  51700. {
  51701. // ...
  51702. }
  51703. ',
  51704. new VersionSpecification(8_04_00)
  51705. ),
  51706. new CodeSample(
  51707. '<?php
  51708. class Sample
  51709. {
  51710. const SAMPLE = 1;
  51711. }
  51712. ',
  51713. ['elements' => ['const']]
  51714. ),
  51715. ]
  51716. );
  51717. }
  51718. public function getPriority(): int
  51719. {
  51720. return 56;
  51721. }
  51722. public function isCandidate(Tokens $tokens): bool
  51723. {
  51724. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  51725. }
  51726. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  51727. {
  51728. $elements = ['const', 'method', 'property'];
  51729. return new FixerConfigurationResolver([
  51730. (new FixerOptionBuilder('elements', 'The structural elements to fix (PHP >= 7.1 required for `const`).'))
  51731. ->setAllowedTypes(['string[]'])
  51732. ->setAllowedValues([new AllowedValueSubset($elements)])
  51733. ->setDefault($elements)
  51734. ->getOption(),
  51735. ]);
  51736. }
  51737. protected function configurePostNormalisation(): void
  51738. {
  51739. $this->elements = $this->configuration['elements'];
  51740. if (\in_array('property', $this->elements, true)) {
  51741. $this->elements[] = 'promoted_property';
  51742. }
  51743. }
  51744. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51745. {
  51746. $tokensAnalyzer = new TokensAnalyzer($tokens);
  51747. foreach (array_reverse($tokensAnalyzer->getClassyElements(), true) as $index => $element) {
  51748. if (!\in_array($element['type'], $this->elements, true)) {
  51749. continue;
  51750. }
  51751. $abstractFinalIndex = null;
  51752. $visibilityIndex = null;
  51753. $visibilitySetIndex = null;
  51754. $staticIndex = null;
  51755. $typeIndex = null;
  51756. $readOnlyIndex = null;
  51757. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  51758. $expectedKinds = 'property' === $element['type'] || 'promoted_property' === $element['type']
  51759. ? self::EXPECTED_KINDS_PROPERTY_KINDS
  51760. : self::EXPECTED_KINDS_GENERIC;
  51761. while ($tokens[$prevIndex]->isGivenKind($expectedKinds) || $tokens[$prevIndex]->equals('&')) {
  51762. if ($tokens[$prevIndex]->isGivenKind([T_ABSTRACT, T_FINAL])) {
  51763. $abstractFinalIndex = $prevIndex;
  51764. } elseif ($tokens[$prevIndex]->isGivenKind(T_STATIC)) {
  51765. $staticIndex = $prevIndex;
  51766. } elseif ($tokens[$prevIndex]->isGivenKind(FCT::T_READONLY)) {
  51767. $readOnlyIndex = $prevIndex;
  51768. } elseif ($tokens[$prevIndex]->isGivenKind([FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET])) {
  51769. $visibilitySetIndex = $prevIndex;
  51770. } elseif ($tokens[$prevIndex]->isGivenKind(self::PROPERTY_TYPE_DECLARATION_KINDS)) {
  51771. $typeIndex = $prevIndex;
  51772. } elseif (!$tokens[$prevIndex]->equals('&')) {
  51773. $visibilityIndex = $prevIndex;
  51774. }
  51775. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  51776. }
  51777. if (null !== $typeIndex) {
  51778. $index = $typeIndex;
  51779. }
  51780. if ('property' === $element['type'] && $tokens[$prevIndex]->equals(',')) {
  51781. continue;
  51782. }
  51783. $swapIndex = $staticIndex ?? $readOnlyIndex;
  51784. if (null !== $swapIndex) {
  51785. if ($this->isKeywordPlacedProperly($tokens, $swapIndex, $index)) {
  51786. $index = $swapIndex;
  51787. } else {
  51788. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $swapIndex, $index);
  51789. }
  51790. }
  51791. if (null !== $visibilitySetIndex) {
  51792. if ($this->isKeywordPlacedProperly($tokens, $visibilitySetIndex, $index)) {
  51793. $index = $visibilitySetIndex;
  51794. } else {
  51795. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $visibilitySetIndex, $index);
  51796. }
  51797. }
  51798. if (null === $visibilityIndex) {
  51799. $tokens->insertAt($index, [new Token(['promoted_property' === $element['type'] ? CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC : T_PUBLIC, 'public']), new Token([T_WHITESPACE, ' '])]);
  51800. } else {
  51801. if ($tokens[$visibilityIndex]->isGivenKind(T_VAR)) {
  51802. $tokens[$visibilityIndex] = new Token([T_PUBLIC, 'public']);
  51803. }
  51804. if ($this->isKeywordPlacedProperly($tokens, $visibilityIndex, $index)) {
  51805. $index = $visibilityIndex;
  51806. } else {
  51807. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $visibilityIndex, $index);
  51808. }
  51809. }
  51810. if (null === $abstractFinalIndex) {
  51811. continue;
  51812. }
  51813. if ($this->isKeywordPlacedProperly($tokens, $abstractFinalIndex, $index)) {
  51814. continue;
  51815. }
  51816. $this->moveTokenAndEnsureSingleSpaceFollows($tokens, $abstractFinalIndex, $index);
  51817. }
  51818. }
  51819. private function isKeywordPlacedProperly(Tokens $tokens, int $keywordIndex, int $comparedIndex): bool
  51820. {
  51821. return ' ' === $tokens[$keywordIndex + 1]->getContent()
  51822. && (
  51823. $keywordIndex + 2 === $comparedIndex
  51824. || $keywordIndex + 3 === $comparedIndex && $tokens[$keywordIndex + 2]->equals('&')
  51825. );
  51826. }
  51827. private function moveTokenAndEnsureSingleSpaceFollows(Tokens $tokens, int $fromIndex, int $toIndex): void
  51828. {
  51829. $tokens->insertAt($toIndex, [$tokens[$fromIndex], new Token([T_WHITESPACE, ' '])]);
  51830. $tokens->clearAt($fromIndex);
  51831. if ($tokens[$fromIndex + 1]->isWhitespace()) {
  51832. $tokens->clearAt($fromIndex + 1);
  51833. }
  51834. }
  51835. }
  51836. <?php
  51837. declare(strict_types=1);
  51838. namespace PhpCsFixer\Fixer\ClassNotation;
  51839. use PhpCsFixer\AbstractFixer;
  51840. use PhpCsFixer\DocBlock\DocBlock;
  51841. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51842. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51843. use PhpCsFixer\FixerDefinition\VersionSpecification;
  51844. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  51845. use PhpCsFixer\Tokenizer\Token;
  51846. use PhpCsFixer\Tokenizer\Tokens;
  51847. final class PhpdocReadonlyClassCommentToKeywordFixer extends AbstractFixer
  51848. {
  51849. public function getPriority(): int
  51850. {
  51851. return 4;
  51852. }
  51853. public function isCandidate(Tokens $tokens): bool
  51854. {
  51855. return \PHP_VERSION_ID >= 8_02_00 && $tokens->isTokenKindFound(T_DOC_COMMENT);
  51856. }
  51857. public function isRisky(): bool
  51858. {
  51859. return true;
  51860. }
  51861. public function getDefinition(): FixerDefinitionInterface
  51862. {
  51863. return new FixerDefinition(
  51864. 'Converts readonly comment on classes to the readonly keyword.',
  51865. [
  51866. new VersionSpecificCodeSample(
  51867. <<<EOT
  51868. <?php
  51869. /** @readonly */
  51870. class C {
  51871. }\n
  51872. EOT,
  51873. new VersionSpecification(8_02_00)
  51874. ),
  51875. ],
  51876. null,
  51877. 'If classes marked with `@readonly` annotation were extended anyway, applying this fixer may break the inheritance for their child classes.'
  51878. );
  51879. }
  51880. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51881. {
  51882. foreach ($tokens as $index => $token) {
  51883. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  51884. continue;
  51885. }
  51886. $doc = new DocBlock($token->getContent());
  51887. $annotations = $doc->getAnnotationsOfType('readonly');
  51888. if (0 === \count($annotations)) {
  51889. continue;
  51890. }
  51891. foreach ($annotations as $annotation) {
  51892. $annotation->remove();
  51893. }
  51894. $mainIndex = $index;
  51895. $index = $tokens->getNextMeaningfulToken($index);
  51896. $addReadonly = true;
  51897. while ($tokens[$index]->isGivenKind([
  51898. T_ABSTRACT,
  51899. T_FINAL,
  51900. T_PRIVATE,
  51901. T_PUBLIC,
  51902. T_PROTECTED,
  51903. T_READONLY,
  51904. ])) {
  51905. if ($tokens[$index]->isGivenKind([T_READONLY])) {
  51906. $addReadonly = false;
  51907. }
  51908. $index = $tokens->getNextMeaningfulToken($index);
  51909. }
  51910. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  51911. continue;
  51912. }
  51913. if ($addReadonly) {
  51914. $tokens->insertAt($index, [new Token([T_READONLY, 'readonly']), new Token([T_WHITESPACE, ' '])]);
  51915. }
  51916. $newContent = $doc->getContent();
  51917. if ('' === $newContent) {
  51918. $tokens->clearTokenAndMergeSurroundingWhitespace($mainIndex);
  51919. continue;
  51920. }
  51921. $tokens[$mainIndex] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  51922. }
  51923. }
  51924. }
  51925. <?php
  51926. declare(strict_types=1);
  51927. namespace PhpCsFixer\Fixer\ClassNotation;
  51928. use PhpCsFixer\AbstractFixer;
  51929. use PhpCsFixer\FixerDefinition\CodeSample;
  51930. use PhpCsFixer\FixerDefinition\FixerDefinition;
  51931. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  51932. use PhpCsFixer\Tokenizer\Token;
  51933. use PhpCsFixer\Tokenizer\Tokens;
  51934. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  51935. final class StaticPrivateMethodFixer extends AbstractFixer
  51936. {
  51937. private const MAGIC_METHODS = [
  51938. '__clone' => true,
  51939. '__construct' => true,
  51940. '__destruct' => true,
  51941. '__wakeup' => true,
  51942. ];
  51943. public function getDefinition(): FixerDefinitionInterface
  51944. {
  51945. return new FixerDefinition(
  51946. 'Converts private methods to `static` where possible.',
  51947. [
  51948. new CodeSample(
  51949. '<?php
  51950. class Foo
  51951. {
  51952. public function bar()
  51953. {
  51954. return $this->baz();
  51955. }
  51956. private function baz()
  51957. {
  51958. return 1;
  51959. }
  51960. }
  51961. '
  51962. ),
  51963. ],
  51964. null,
  51965. 'Risky when the method:'
  51966. .' contains dynamic generated calls to the instance,'
  51967. .' is dynamically referenced,'
  51968. .' is referenced inside a Trait the class uses.'
  51969. );
  51970. }
  51971. public function getPriority(): int
  51972. {
  51973. return 1;
  51974. }
  51975. public function isCandidate(Tokens $tokens): bool
  51976. {
  51977. return $tokens->isAllTokenKindsFound([T_CLASS, T_PRIVATE, T_FUNCTION]);
  51978. }
  51979. public function isRisky(): bool
  51980. {
  51981. return true;
  51982. }
  51983. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  51984. {
  51985. $tokensAnalyzer = new TokensAnalyzer($tokens);
  51986. do {
  51987. $anythingChanged = false;
  51988. $end = \count($tokens) - 3;
  51989. for ($index = $end; $index > 0; --$index) {
  51990. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  51991. continue;
  51992. }
  51993. $classOpen = $tokens->getNextTokenOfKind($index, ['{']);
  51994. $classClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  51995. $anythingChanged |= $this->fixClass($tokens, $tokensAnalyzer, $classOpen, $classClose);
  51996. }
  51997. } while ($anythingChanged);
  51998. }
  51999. private function fixClass(Tokens $tokens, TokensAnalyzer $tokensAnalyzer, int $classOpen, int $classClose): bool
  52000. {
  52001. $fixedMethods = [];
  52002. foreach ($this->getClassMethods($tokens, $classOpen, $classClose) as $methodData) {
  52003. [$functionKeywordIndex, $methodOpen, $methodClose] = $methodData;
  52004. if ($this->skipMethod($tokens, $tokensAnalyzer, $functionKeywordIndex, $methodOpen, $methodClose)) {
  52005. continue;
  52006. }
  52007. $methodNameIndex = $tokens->getNextMeaningfulToken($functionKeywordIndex);
  52008. $methodName = $tokens[$methodNameIndex]->getContent();
  52009. $fixedMethods[$methodName] = true;
  52010. $tokens->insertSlices([$functionKeywordIndex => [new Token([T_STATIC, 'static']), new Token([T_WHITESPACE, ' '])]]);
  52011. }
  52012. if (0 === \count($fixedMethods)) {
  52013. return false;
  52014. }
  52015. $classClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpen);
  52016. foreach ($this->getClassMethods($tokens, $classOpen, $classClose) as $methodData) {
  52017. [, $methodOpen, $methodClose] = $methodData;
  52018. $this->fixReferencesInFunction($tokens, $tokensAnalyzer, $methodOpen, $methodClose, $fixedMethods);
  52019. }
  52020. return true;
  52021. }
  52022. private function skipMethod(Tokens $tokens, TokensAnalyzer $tokensAnalyzer, int $functionKeywordIndex, int $methodOpen, int $methodClose): bool
  52023. {
  52024. $methodNameIndex = $tokens->getNextMeaningfulToken($functionKeywordIndex);
  52025. $methodName = strtolower($tokens[$methodNameIndex]->getContent());
  52026. if (isset(self::MAGIC_METHODS[$methodName])) {
  52027. return true;
  52028. }
  52029. $prevTokenIndex = $tokens->getPrevMeaningfulToken($functionKeywordIndex);
  52030. if ($tokens[$prevTokenIndex]->isGivenKind(T_FINAL)) {
  52031. $prevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex);
  52032. }
  52033. if (!$tokens[$prevTokenIndex]->isGivenKind(T_PRIVATE)) {
  52034. return true;
  52035. }
  52036. $prePrevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex);
  52037. if ($tokens[$prePrevTokenIndex]->isGivenKind(T_STATIC)) {
  52038. return true;
  52039. }
  52040. for ($index = $methodOpen + 1; $index < $methodClose - 1; ++$index) {
  52041. if ($tokens[$index]->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($index)) {
  52042. $anonymousClassOpen = $tokens->getNextTokenOfKind($index, ['{']);
  52043. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $anonymousClassOpen);
  52044. continue;
  52045. }
  52046. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  52047. return true;
  52048. }
  52049. if ($tokens[$index]->equals([T_VARIABLE, '$this'])) {
  52050. $operatorIndex = $tokens->getNextMeaningfulToken($index);
  52051. $methodNameIndex = $tokens->getNextMeaningfulToken($operatorIndex);
  52052. $argumentsBraceIndex = $tokens->getNextMeaningfulToken($methodNameIndex);
  52053. if (
  52054. !$tokens[$operatorIndex]->isGivenKind(T_OBJECT_OPERATOR)
  52055. || $methodName !== $tokens[$methodNameIndex]->getContent()
  52056. || !$tokens[$argumentsBraceIndex]->equals('(')
  52057. ) {
  52058. return true;
  52059. }
  52060. }
  52061. if ($tokens[$index]->equals([T_STRING, 'debug_backtrace'])) {
  52062. return true;
  52063. }
  52064. }
  52065. return false;
  52066. }
  52067. private function fixReferencesInFunction(Tokens $tokens, TokensAnalyzer $tokensAnalyzer, int $methodOpen, int $methodClose, array $fixedMethods): void
  52068. {
  52069. for ($index = $methodOpen + 1; $index < $methodClose - 1; ++$index) {
  52070. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  52071. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  52072. $closureStart = $tokens->getNextTokenOfKind($index, ['{']);
  52073. $closureEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $closureStart);
  52074. if (!$tokens[$prevIndex]->isGivenKind(T_STATIC)) {
  52075. $this->fixReferencesInFunction($tokens, $tokensAnalyzer, $closureStart, $closureEnd, $fixedMethods);
  52076. }
  52077. $index = $closureEnd;
  52078. continue;
  52079. }
  52080. if ($tokens[$index]->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($index)) {
  52081. $anonymousClassOpen = $tokens->getNextTokenOfKind($index, ['{']);
  52082. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $anonymousClassOpen);
  52083. continue;
  52084. }
  52085. if (!$tokens[$index]->equals([T_VARIABLE, '$this'])) {
  52086. continue;
  52087. }
  52088. $objectOperatorIndex = $tokens->getNextMeaningfulToken($index);
  52089. if (!$tokens[$objectOperatorIndex]->isGivenKind(T_OBJECT_OPERATOR)) {
  52090. continue;
  52091. }
  52092. $methodNameIndex = $tokens->getNextMeaningfulToken($objectOperatorIndex);
  52093. $argumentsBraceIndex = $tokens->getNextMeaningfulToken($methodNameIndex);
  52094. if (!$tokens[$argumentsBraceIndex]->equals('(')) {
  52095. continue;
  52096. }
  52097. $currentMethodName = $tokens[$methodNameIndex]->getContent();
  52098. if (!isset($fixedMethods[$currentMethodName])) {
  52099. continue;
  52100. }
  52101. $tokens[$index] = new Token([T_STRING, 'self']);
  52102. $tokens[$objectOperatorIndex] = new Token([T_DOUBLE_COLON, '::']);
  52103. }
  52104. }
  52105. private function getClassMethods(Tokens $tokens, int $classOpen, int $classClose): array
  52106. {
  52107. $methods = [];
  52108. for ($index = $classClose - 1; $index > $classOpen + 1; --$index) {
  52109. if ($tokens[$index]->equals('}')) {
  52110. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  52111. continue;
  52112. }
  52113. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  52114. continue;
  52115. }
  52116. $functionKeywordIndex = $index;
  52117. $prevTokenIndex = $tokens->getPrevMeaningfulToken($functionKeywordIndex);
  52118. $prevPrevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex);
  52119. if ($tokens[$prevTokenIndex]->isGivenKind(T_ABSTRACT) || $tokens[$prevPrevTokenIndex]->isGivenKind(T_ABSTRACT)) {
  52120. continue;
  52121. }
  52122. $methodOpen = $tokens->getNextTokenOfKind($functionKeywordIndex, ['{']);
  52123. $methodClose = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $methodOpen);
  52124. $methods[] = [$functionKeywordIndex, $methodOpen, $methodClose];
  52125. }
  52126. return $methods;
  52127. }
  52128. }
  52129. <?php
  52130. declare(strict_types=1);
  52131. namespace PhpCsFixer\Fixer\ClassNotation;
  52132. use PhpCsFixer\AbstractFixer;
  52133. use PhpCsFixer\FixerDefinition\CodeSample;
  52134. use PhpCsFixer\FixerDefinition\FixerDefinition;
  52135. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  52136. use PhpCsFixer\Preg;
  52137. use PhpCsFixer\Tokenizer\CT;
  52138. use PhpCsFixer\Tokenizer\Token;
  52139. use PhpCsFixer\Tokenizer\Tokens;
  52140. final class SingleTraitInsertPerStatementFixer extends AbstractFixer
  52141. {
  52142. public function getDefinition(): FixerDefinitionInterface
  52143. {
  52144. return new FixerDefinition(
  52145. 'Each trait `use` must be done as single statement.',
  52146. [
  52147. new CodeSample(
  52148. '<?php
  52149. final class Example
  52150. {
  52151. use Foo, Bar;
  52152. }
  52153. '
  52154. ),
  52155. ]
  52156. );
  52157. }
  52158. public function getPriority(): int
  52159. {
  52160. return 36;
  52161. }
  52162. public function isCandidate(Tokens $tokens): bool
  52163. {
  52164. return $tokens->isTokenKindFound(CT::T_USE_TRAIT);
  52165. }
  52166. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  52167. {
  52168. for ($index = \count($tokens) - 1; 1 < $index; --$index) {
  52169. if ($tokens[$index]->isGivenKind(CT::T_USE_TRAIT)) {
  52170. $candidates = $this->getCandidates($tokens, $index);
  52171. if (\count($candidates) > 0) {
  52172. $this->fixTraitUse($tokens, $index, $candidates);
  52173. }
  52174. }
  52175. }
  52176. }
  52177. private function fixTraitUse(Tokens $tokens, int $useTraitIndex, array $candidates): void
  52178. {
  52179. foreach ($candidates as $commaIndex) {
  52180. $inserts = [
  52181. new Token([CT::T_USE_TRAIT, 'use']),
  52182. new Token([T_WHITESPACE, ' ']),
  52183. ];
  52184. $nextImportStartIndex = $tokens->getNextMeaningfulToken($commaIndex);
  52185. if ($tokens[$nextImportStartIndex - 1]->isWhitespace()) {
  52186. if (Preg::match('/\R/', $tokens[$nextImportStartIndex - 1]->getContent())) {
  52187. array_unshift($inserts, clone $tokens[$useTraitIndex - 1]);
  52188. }
  52189. $tokens->clearAt($nextImportStartIndex - 1);
  52190. }
  52191. $tokens[$commaIndex] = new Token(';');
  52192. $tokens->insertAt($nextImportStartIndex, $inserts);
  52193. }
  52194. }
  52195. private function getCandidates(Tokens $tokens, int $index): array
  52196. {
  52197. $indices = [];
  52198. $index = $tokens->getNextTokenOfKind($index, [',', ';', '{']);
  52199. while (!$tokens[$index]->equals(';')) {
  52200. if ($tokens[$index]->equals('{')) {
  52201. return [];
  52202. }
  52203. $indices[] = $index;
  52204. $index = $tokens->getNextTokenOfKind($index, [',', ';', '{']);
  52205. }
  52206. return array_reverse($indices);
  52207. }
  52208. }
  52209. <?php
  52210. declare(strict_types=1);
  52211. namespace PhpCsFixer\Fixer\ControlStructure;
  52212. use PhpCsFixer\AbstractProxyFixer;
  52213. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  52214. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  52215. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  52216. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  52217. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  52218. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  52219. use PhpCsFixer\FixerDefinition\FixerDefinition;
  52220. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  52221. /**
  52222. @phpstan-type
  52223. @phpstan-type
  52224. @implements
  52225. */
  52226. final class NoUnneededCurlyBracesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface
  52227. {
  52228. /**
  52229. @use */
  52230. use ConfigurableFixerTrait;
  52231. private NoUnneededBracesFixer $noUnneededBracesFixer;
  52232. public function __construct()
  52233. {
  52234. $this->noUnneededBracesFixer = new NoUnneededBracesFixer();
  52235. parent::__construct();
  52236. }
  52237. public function getDefinition(): FixerDefinitionInterface
  52238. {
  52239. $fixerDefinition = $this->noUnneededBracesFixer->getDefinition();
  52240. return new FixerDefinition(
  52241. 'Removes unneeded curly braces that are superfluous and aren\'t part of a control structure\'s body.',
  52242. $fixerDefinition->getCodeSamples(),
  52243. $fixerDefinition->getDescription(),
  52244. $fixerDefinition->getRiskyDescription()
  52245. );
  52246. }
  52247. public function getPriority(): int
  52248. {
  52249. return $this->noUnneededBracesFixer->getPriority();
  52250. }
  52251. public function getSuccessorsNames(): array
  52252. {
  52253. return [
  52254. $this->noUnneededBracesFixer->getName(),
  52255. ];
  52256. }
  52257. protected function configurePreNormalisation(array $configuration): void
  52258. {
  52259. $this->noUnneededBracesFixer->configure($configuration);
  52260. }
  52261. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  52262. {
  52263. return new FixerConfigurationResolver([
  52264. (new FixerOptionBuilder('namespaces', 'Remove unneeded curly braces from bracketed namespaces.'))
  52265. ->setAllowedTypes(['bool'])
  52266. ->setDefault(false)
  52267. ->getOption(),
  52268. ]);
  52269. }
  52270. protected function createProxyFixers(): array
  52271. {
  52272. return [
  52273. $this->noUnneededBracesFixer,
  52274. ];
  52275. }
  52276. }
  52277. <?php
  52278. declare(strict_types=1);
  52279. namespace PhpCsFixer\Fixer\ControlStructure;
  52280. use PhpCsFixer\AbstractFixer;
  52281. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  52282. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  52283. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  52284. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  52285. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  52286. use PhpCsFixer\FixerDefinition\CodeSample;
  52287. use PhpCsFixer\FixerDefinition\FixerDefinition;
  52288. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  52289. use PhpCsFixer\Tokenizer\Token;
  52290. use PhpCsFixer\Tokenizer\Tokens;
  52291. /**
  52292. @phpstan-type
  52293. @phpstan-type
  52294. @implements
  52295. */
  52296. final class NoAlternativeSyntaxFixer extends AbstractFixer implements ConfigurableFixerInterface
  52297. {
  52298. /**
  52299. @use */
  52300. use ConfigurableFixerTrait;
  52301. public function getDefinition(): FixerDefinitionInterface
  52302. {
  52303. return new FixerDefinition(
  52304. 'Replace control structure alternative syntax to use braces.',
  52305. [
  52306. new CodeSample(
  52307. "<?php\nif(true):echo 't';else:echo 'f';endif;\n"
  52308. ),
  52309. new CodeSample(
  52310. "<?php if (\$condition): ?>\nLorem ipsum.\n<?php endif; ?>\n",
  52311. ['fix_non_monolithic_code' => true]
  52312. ),
  52313. ]
  52314. );
  52315. }
  52316. public function isCandidate(Tokens $tokens): bool
  52317. {
  52318. return $tokens->hasAlternativeSyntax() && (true === $this->configuration['fix_non_monolithic_code'] || $tokens->isMonolithicPhp());
  52319. }
  52320. public function getPriority(): int
  52321. {
  52322. return 42;
  52323. }
  52324. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  52325. {
  52326. return new FixerConfigurationResolver([
  52327. (new FixerOptionBuilder('fix_non_monolithic_code', 'Whether to also fix code with inline HTML.'))
  52328. ->setAllowedTypes(['bool'])
  52329. ->setDefault(true)
  52330. ->getOption(),
  52331. ]);
  52332. }
  52333. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  52334. {
  52335. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  52336. $token = $tokens[$index];
  52337. $this->fixElseif($index, $token, $tokens);
  52338. $this->fixElse($index, $token, $tokens);
  52339. $this->fixOpenCloseControls($index, $token, $tokens);
  52340. }
  52341. }
  52342. private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
  52343. {
  52344. $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
  52345. $nextToken = $tokens[$nextIndex];
  52346. return $nextToken->equals('(')
  52347. ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex)
  52348. : $structureTokenIndex;
  52349. }
  52350. private function fixOpenCloseControls(int $index, Token $token, Tokens $tokens): void
  52351. {
  52352. if ($token->isGivenKind([T_IF, T_FOREACH, T_WHILE, T_FOR, T_SWITCH, T_DECLARE])) {
  52353. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  52354. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  52355. $afterParenthesisIndex = $tokens->getNextMeaningfulToken($closeIndex);
  52356. $afterParenthesis = $tokens[$afterParenthesisIndex];
  52357. if (!$afterParenthesis->equals(':')) {
  52358. return;
  52359. }
  52360. $items = [];
  52361. if (!$tokens[$afterParenthesisIndex - 1]->isWhitespace()) {
  52362. $items[] = new Token([T_WHITESPACE, ' ']);
  52363. }
  52364. $items[] = new Token('{');
  52365. if (!$tokens[$afterParenthesisIndex + 1]->isWhitespace()) {
  52366. $items[] = new Token([T_WHITESPACE, ' ']);
  52367. }
  52368. $tokens->clearAt($afterParenthesisIndex);
  52369. $tokens->insertAt($afterParenthesisIndex, $items);
  52370. }
  52371. if (!$token->isGivenKind([T_ENDIF, T_ENDFOREACH, T_ENDWHILE, T_ENDFOR, T_ENDSWITCH, T_ENDDECLARE])) {
  52372. return;
  52373. }
  52374. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  52375. $nextToken = $tokens[$nextTokenIndex];
  52376. $tokens[$index] = new Token('}');
  52377. if ($nextToken->equals(';')) {
  52378. $tokens->clearAt($nextTokenIndex);
  52379. }
  52380. }
  52381. private function fixElse(int $index, Token $token, Tokens $tokens): void
  52382. {
  52383. if (!$token->isGivenKind(T_ELSE)) {
  52384. return;
  52385. }
  52386. $tokenAfterElseIndex = $tokens->getNextMeaningfulToken($index);
  52387. $tokenAfterElse = $tokens[$tokenAfterElseIndex];
  52388. if (!$tokenAfterElse->equals(':')) {
  52389. return;
  52390. }
  52391. $this->addBraces($tokens, new Token([T_ELSE, 'else']), $index, $tokenAfterElseIndex);
  52392. }
  52393. private function fixElseif(int $index, Token $token, Tokens $tokens): void
  52394. {
  52395. if (!$token->isGivenKind(T_ELSEIF)) {
  52396. return;
  52397. }
  52398. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  52399. $tokenAfterParenthesisIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  52400. $tokenAfterParenthesis = $tokens[$tokenAfterParenthesisIndex];
  52401. if (!$tokenAfterParenthesis->equals(':')) {
  52402. return;
  52403. }
  52404. $this->addBraces($tokens, new Token([T_ELSEIF, 'elseif']), $index, $tokenAfterParenthesisIndex);
  52405. }
  52406. private function addBraces(Tokens $tokens, Token $token, int $index, int $colonIndex): void
  52407. {
  52408. $items = [
  52409. new Token('}'),
  52410. new Token([T_WHITESPACE, ' ']),
  52411. $token,
  52412. ];
  52413. if (!$tokens[$index + 1]->isWhitespace()) {
  52414. $items[] = new Token([T_WHITESPACE, ' ']);
  52415. }
  52416. $tokens->clearAt($index);
  52417. $tokens->insertAt(
  52418. $index,
  52419. $items
  52420. );
  52421. $colonIndex += \count($items);
  52422. $items = [new Token('{')];
  52423. if (!$tokens[$colonIndex + 1]->isWhitespace()) {
  52424. $items[] = new Token([T_WHITESPACE, ' ']);
  52425. }
  52426. $tokens->clearAt($colonIndex);
  52427. $tokens->insertAt(
  52428. $colonIndex,
  52429. $items
  52430. );
  52431. }
  52432. }
  52433. <?php
  52434. declare(strict_types=1);
  52435. namespace PhpCsFixer\Fixer\ControlStructure;
  52436. use PhpCsFixer\AbstractFixer;
  52437. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  52438. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  52439. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  52440. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  52441. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  52442. use PhpCsFixer\FixerDefinition\CodeSample;
  52443. use PhpCsFixer\FixerDefinition\FixerDefinition;
  52444. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  52445. use PhpCsFixer\Tokenizer\CT;
  52446. use PhpCsFixer\Tokenizer\Token;
  52447. use PhpCsFixer\Tokenizer\Tokens;
  52448. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  52449. /**
  52450. @phpstan-type
  52451. @phpstan-type
  52452. @implements
  52453. */
  52454. final class YodaStyleFixer extends AbstractFixer implements ConfigurableFixerInterface
  52455. {
  52456. /**
  52457. @use */
  52458. use ConfigurableFixerTrait;
  52459. private array $candidatesMap;
  52460. private array $candidateTypesConfiguration;
  52461. private array $candidateTypes;
  52462. public function getDefinition(): FixerDefinitionInterface
  52463. {
  52464. return new FixerDefinition(
  52465. 'Write conditions in Yoda style (`true`), non-Yoda style (`[\'equal\' => false, \'identical\' => false, \'less_and_greater\' => false]`) or ignore those conditions (`null`) based on configuration.',
  52466. [
  52467. new CodeSample(
  52468. '<?php
  52469. if ($a === null) {
  52470. echo "null";
  52471. }
  52472. '
  52473. ),
  52474. new CodeSample(
  52475. '<?php
  52476. $b = $c != 1; // equal
  52477. $a = 1 === $b; // identical
  52478. $c = $c > 3; // less than
  52479. ',
  52480. [
  52481. 'equal' => true,
  52482. 'identical' => false,
  52483. 'less_and_greater' => null,
  52484. ]
  52485. ),
  52486. new CodeSample(
  52487. '<?php
  52488. return $foo === count($bar);
  52489. ',
  52490. [
  52491. 'always_move_variable' => true,
  52492. ]
  52493. ),
  52494. new CodeSample(
  52495. '<?php
  52496. // Enforce non-Yoda style.
  52497. if (null === $a) {
  52498. echo "null";
  52499. }
  52500. ',
  52501. [
  52502. 'equal' => false,
  52503. 'identical' => false,
  52504. 'less_and_greater' => false,
  52505. ]
  52506. ),
  52507. ]
  52508. );
  52509. }
  52510. public function getPriority(): int
  52511. {
  52512. return 0;
  52513. }
  52514. public function isCandidate(Tokens $tokens): bool
  52515. {
  52516. return $tokens->isAnyTokenKindsFound($this->candidateTypes);
  52517. }
  52518. protected function configurePostNormalisation(): void
  52519. {
  52520. $this->resolveConfiguration();
  52521. }
  52522. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  52523. {
  52524. $this->fixTokens($tokens);
  52525. }
  52526. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  52527. {
  52528. return new FixerConfigurationResolver([
  52529. (new FixerOptionBuilder('equal', 'Style for equal (`==`, `!=`) statements.'))
  52530. ->setAllowedTypes(['bool', 'null'])
  52531. ->setDefault(true)
  52532. ->getOption(),
  52533. (new FixerOptionBuilder('identical', 'Style for identical (`===`, `!==`) statements.'))
  52534. ->setAllowedTypes(['bool', 'null'])
  52535. ->setDefault(true)
  52536. ->getOption(),
  52537. (new FixerOptionBuilder('less_and_greater', 'Style for less and greater than (`<`, `<=`, `>`, `>=`) statements.'))
  52538. ->setAllowedTypes(['bool', 'null'])
  52539. ->setDefault(null)
  52540. ->getOption(),
  52541. (new FixerOptionBuilder('always_move_variable', 'Whether variables should always be on non assignable side when applying Yoda style.'))
  52542. ->setAllowedTypes(['bool'])
  52543. ->setDefault(false)
  52544. ->getOption(),
  52545. ]);
  52546. }
  52547. private function findComparisonEnd(Tokens $tokens, int $index): int
  52548. {
  52549. ++$index;
  52550. $count = \count($tokens);
  52551. while ($index < $count) {
  52552. $token = $tokens[$index];
  52553. if ($token->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  52554. ++$index;
  52555. continue;
  52556. }
  52557. if ($this->isOfLowerPrecedence($token)) {
  52558. break;
  52559. }
  52560. $block = Tokens::detectBlockType($token);
  52561. if (null === $block) {
  52562. ++$index;
  52563. continue;
  52564. }
  52565. if (!$block['isStart']) {
  52566. break;
  52567. }
  52568. $index = $tokens->findBlockEnd($block['type'], $index) + 1;
  52569. }
  52570. $prev = $tokens->getPrevMeaningfulToken($index);
  52571. return $tokens[$prev]->isGivenKind(T_CLOSE_TAG) ? $tokens->getPrevMeaningfulToken($prev) : $prev;
  52572. }
  52573. private function findComparisonStart(Tokens $tokens, int $index): int
  52574. {
  52575. --$index;
  52576. $nonBlockFound = false;
  52577. while (0 <= $index) {
  52578. $token = $tokens[$index];
  52579. if ($token->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  52580. --$index;
  52581. continue;
  52582. }
  52583. if ($token->isGivenKind([CT::T_NAMED_ARGUMENT_COLON])) {
  52584. break;
  52585. }
  52586. if ($this->isOfLowerPrecedence($token)) {
  52587. break;
  52588. }
  52589. $block = Tokens::detectBlockType($token);
  52590. if (null === $block) {
  52591. --$index;
  52592. $nonBlockFound = true;
  52593. continue;
  52594. }
  52595. if (
  52596. $block['isStart']
  52597. || ($nonBlockFound && Tokens::BLOCK_TYPE_CURLY_BRACE === $block['type'])
  52598. ) {
  52599. break;
  52600. }
  52601. $index = $tokens->findBlockStart($block['type'], $index) - 1;
  52602. }
  52603. return $tokens->getNextMeaningfulToken($index);
  52604. }
  52605. private function fixTokens(Tokens $tokens): Tokens
  52606. {
  52607. for ($i = \count($tokens) - 1; $i > 1; --$i) {
  52608. if ($tokens[$i]->isGivenKind($this->candidateTypes)) {
  52609. $yoda = $this->candidateTypesConfiguration[$tokens[$i]->getId()];
  52610. } elseif (
  52611. ($tokens[$i]->equals('<') && \in_array('<', $this->candidateTypes, true))
  52612. || ($tokens[$i]->equals('>') && \in_array('>', $this->candidateTypes, true))
  52613. ) {
  52614. $yoda = $this->candidateTypesConfiguration[$tokens[$i]->getContent()];
  52615. } else {
  52616. continue;
  52617. }
  52618. $fixableCompareInfo = $this->getCompareFixableInfo($tokens, $i, $yoda);
  52619. if (null === $fixableCompareInfo) {
  52620. continue;
  52621. }
  52622. $i = $this->fixTokensCompare(
  52623. $tokens,
  52624. $fixableCompareInfo['left']['start'],
  52625. $fixableCompareInfo['left']['end'],
  52626. $i,
  52627. $fixableCompareInfo['right']['start'],
  52628. $fixableCompareInfo['right']['end']
  52629. );
  52630. }
  52631. return $tokens;
  52632. }
  52633. private function fixTokensCompare(
  52634. Tokens $tokens,
  52635. int $startLeft,
  52636. int $endLeft,
  52637. int $compareOperatorIndex,
  52638. int $startRight,
  52639. int $endRight
  52640. ): int {
  52641. $type = $tokens[$compareOperatorIndex]->getId();
  52642. $content = $tokens[$compareOperatorIndex]->getContent();
  52643. if (\array_key_exists($type, $this->candidatesMap)) {
  52644. $tokens[$compareOperatorIndex] = clone $this->candidatesMap[$type];
  52645. } elseif (\array_key_exists($content, $this->candidatesMap)) {
  52646. $tokens[$compareOperatorIndex] = clone $this->candidatesMap[$content];
  52647. }
  52648. $right = $this->fixTokensComparePart($tokens, $startRight, $endRight);
  52649. $left = $this->fixTokensComparePart($tokens, $startLeft, $endLeft);
  52650. for ($i = $startRight; $i <= $endRight; ++$i) {
  52651. $tokens->clearAt($i);
  52652. }
  52653. for ($i = $startLeft; $i <= $endLeft; ++$i) {
  52654. $tokens->clearAt($i);
  52655. }
  52656. $tokens->insertAt($startRight, $left);
  52657. $tokens->insertAt($startLeft, $right);
  52658. return $startLeft;
  52659. }
  52660. private function fixTokensComparePart(Tokens $tokens, int $start, int $end): Tokens
  52661. {
  52662. $newTokens = $tokens->generatePartialCode($start, $end);
  52663. $newTokens = $this->fixTokens(Tokens::fromCode(\sprintf('<?php %s;', $newTokens)));
  52664. $newTokens->clearAt(\count($newTokens) - 1);
  52665. $newTokens->clearAt(0);
  52666. $newTokens->clearEmptyTokens();
  52667. return $newTokens;
  52668. }
  52669. private function getCompareFixableInfo(Tokens $tokens, int $index, bool $yoda): ?array
  52670. {
  52671. $right = $this->getRightSideCompareFixableInfo($tokens, $index);
  52672. if (!$yoda && $this->isOfLowerPrecedenceAssignment($tokens[$tokens->getNextMeaningfulToken($right['end'])])) {
  52673. return null;
  52674. }
  52675. $left = $this->getLeftSideCompareFixableInfo($tokens, $index);
  52676. if ($this->isListStatement($tokens, $left['start'], $left['end']) || $this->isListStatement($tokens, $right['start'], $right['end'])) {
  52677. return null;
  52678. }
  52679. $strict = $this->configuration['always_move_variable'];
  52680. $leftSideIsVariable = $this->isVariable($tokens, $left['start'], $left['end'], $strict);
  52681. $rightSideIsVariable = $this->isVariable($tokens, $right['start'], $right['end'], $strict);
  52682. if (!($leftSideIsVariable xor $rightSideIsVariable)) {
  52683. return null;
  52684. }
  52685. if (!$strict) {
  52686. $leftSideIsVariable = $leftSideIsVariable && !$tokens[$left['start']]->equals('(');
  52687. $rightSideIsVariable = $rightSideIsVariable && !$tokens[$right['start']]->equals('(');
  52688. }
  52689. return ($yoda && !$leftSideIsVariable) || (!$yoda && !$rightSideIsVariable)
  52690. ? null
  52691. : ['left' => $left, 'right' => $right];
  52692. }
  52693. private function getLeftSideCompareFixableInfo(Tokens $tokens, int $index): array
  52694. {
  52695. return [
  52696. 'start' => $this->findComparisonStart($tokens, $index),
  52697. 'end' => $tokens->getPrevMeaningfulToken($index),
  52698. ];
  52699. }
  52700. private function getRightSideCompareFixableInfo(Tokens $tokens, int $index): array
  52701. {
  52702. return [
  52703. 'start' => $tokens->getNextMeaningfulToken($index),
  52704. 'end' => $this->findComparisonEnd($tokens, $index),
  52705. ];
  52706. }
  52707. private function isListStatement(Tokens $tokens, int $index, int $end): bool
  52708. {
  52709. for ($i = $index; $i <= $end; ++$i) {
  52710. if ($tokens[$i]->isGivenKind([T_LIST, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE])) {
  52711. return true;
  52712. }
  52713. }
  52714. return false;
  52715. }
  52716. private function isOfLowerPrecedence(Token $token): bool
  52717. {
  52718. static $tokens;
  52719. if (null === $tokens) {
  52720. $tokens = [
  52721. T_BOOLEAN_AND,
  52722. T_BOOLEAN_OR,
  52723. T_CASE,
  52724. T_DOUBLE_ARROW,
  52725. T_ECHO,
  52726. T_GOTO,
  52727. T_LOGICAL_AND,
  52728. T_LOGICAL_OR,
  52729. T_LOGICAL_XOR,
  52730. T_OPEN_TAG,
  52731. T_OPEN_TAG_WITH_ECHO,
  52732. T_PRINT,
  52733. T_RETURN,
  52734. T_THROW,
  52735. T_COALESCE,
  52736. T_YIELD,
  52737. T_YIELD_FROM,
  52738. T_REQUIRE,
  52739. T_REQUIRE_ONCE,
  52740. T_INCLUDE,
  52741. T_INCLUDE_ONCE,
  52742. ];
  52743. }
  52744. static $otherTokens = [
  52745. '&', '|', '^',
  52746. '?', ':',
  52747. ',', ';',
  52748. ];
  52749. return $this->isOfLowerPrecedenceAssignment($token) || $token->isGivenKind($tokens) || $token->equalsAny($otherTokens);
  52750. }
  52751. private function isOfLowerPrecedenceAssignment(Token $token): bool
  52752. {
  52753. static $tokens;
  52754. if (null === $tokens) {
  52755. $tokens = [
  52756. T_AND_EQUAL,
  52757. T_CONCAT_EQUAL,
  52758. T_DIV_EQUAL,
  52759. T_MINUS_EQUAL,
  52760. T_MOD_EQUAL,
  52761. T_MUL_EQUAL,
  52762. T_OR_EQUAL,
  52763. T_PLUS_EQUAL,
  52764. T_POW_EQUAL,
  52765. T_SL_EQUAL,
  52766. T_SR_EQUAL,
  52767. T_XOR_EQUAL,
  52768. T_COALESCE_EQUAL,
  52769. ];
  52770. }
  52771. return $token->equals('=') || $token->isGivenKind($tokens);
  52772. }
  52773. private function isVariable(Tokens $tokens, int $start, int $end, bool $strict): bool
  52774. {
  52775. $tokenAnalyzer = new TokensAnalyzer($tokens);
  52776. if ($start === $end) {
  52777. return $tokens[$start]->isGivenKind(T_VARIABLE);
  52778. }
  52779. if ($tokens[$start]->equals('(')) {
  52780. return true;
  52781. }
  52782. if ($strict) {
  52783. for ($index = $start; $index <= $end; ++$index) {
  52784. if (
  52785. $tokens[$index]->isCast()
  52786. || $tokens[$index]->isGivenKind(T_INSTANCEOF)
  52787. || $tokens[$index]->equals('!')
  52788. || $tokenAnalyzer->isBinaryOperator($index)
  52789. ) {
  52790. return false;
  52791. }
  52792. }
  52793. }
  52794. $index = $start;
  52795. while (
  52796. $tokens[$index]->equals('(')
  52797. && $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index) === $end
  52798. ) {
  52799. $index = $tokens->getNextMeaningfulToken($index);
  52800. $end = $tokens->getPrevMeaningfulToken($end);
  52801. }
  52802. $expectString = false;
  52803. while ($index <= $end) {
  52804. $current = $tokens[$index];
  52805. if ($current->isComment() || $current->isWhitespace() || $tokens->isEmptyAt($index)) {
  52806. ++$index;
  52807. continue;
  52808. }
  52809. if ($index === $end) {
  52810. return $current->isGivenKind($expectString ? T_STRING : T_VARIABLE);
  52811. }
  52812. if ($current->isGivenKind([T_LIST, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE])) {
  52813. return false;
  52814. }
  52815. $nextIndex = $tokens->getNextMeaningfulToken($index);
  52816. $next = $tokens[$nextIndex];
  52817. if ($current->isGivenKind(T_STRING) && $next->isGivenKind(T_DOUBLE_COLON)) {
  52818. $index = $tokens->getNextMeaningfulToken($nextIndex);
  52819. continue;
  52820. }
  52821. if ($current->isGivenKind(T_NS_SEPARATOR) && $next->isGivenKind(T_STRING)) {
  52822. $index = $nextIndex;
  52823. continue;
  52824. }
  52825. if ($current->isGivenKind(T_STRING) && $next->isGivenKind(T_NS_SEPARATOR)) {
  52826. $index = $nextIndex;
  52827. continue;
  52828. }
  52829. if ($current->isGivenKind([T_STRING, T_VARIABLE]) && $next->isObjectOperator()) {
  52830. $index = $tokens->getNextMeaningfulToken($nextIndex);
  52831. $expectString = true;
  52832. continue;
  52833. }
  52834. if (
  52835. $current->isGivenKind($expectString ? T_STRING : T_VARIABLE)
  52836. && $next->equalsAny(['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']])
  52837. ) {
  52838. $index = $tokens->findBlockEnd(
  52839. $next->equals('[') ? Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE : Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE,
  52840. $nextIndex
  52841. );
  52842. if ($index === $end) {
  52843. return true;
  52844. }
  52845. $index = $tokens->getNextMeaningfulToken($index);
  52846. if (!$tokens[$index]->equalsAny(['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']]) && !$tokens[$index]->isObjectOperator()) {
  52847. return false;
  52848. }
  52849. $index = $tokens->getNextMeaningfulToken($index);
  52850. $expectString = true;
  52851. continue;
  52852. }
  52853. if ($strict && $current->isGivenKind([T_STRING, T_VARIABLE]) && $next->equals('(')) {
  52854. return false;
  52855. }
  52856. if ($expectString && $current->isGivenKind(CT::T_DYNAMIC_PROP_BRACE_OPEN)) {
  52857. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_PROP_BRACE, $index);
  52858. if ($index === $end) {
  52859. return true;
  52860. }
  52861. $index = $tokens->getNextMeaningfulToken($index);
  52862. if (!$tokens[$index]->isObjectOperator()) {
  52863. return false;
  52864. }
  52865. $index = $tokens->getNextMeaningfulToken($index);
  52866. $expectString = true;
  52867. continue;
  52868. }
  52869. break;
  52870. }
  52871. return !$this->isConstant($tokens, $start, $end);
  52872. }
  52873. private function isConstant(Tokens $tokens, int $index, int $end): bool
  52874. {
  52875. $expectArrayOnly = false;
  52876. $expectNumberOnly = false;
  52877. $expectNothing = false;
  52878. for (; $index <= $end; ++$index) {
  52879. $token = $tokens[$index];
  52880. if ($token->isComment() || $token->isWhitespace()) {
  52881. continue;
  52882. }
  52883. if ($expectNothing) {
  52884. return false;
  52885. }
  52886. if ($expectArrayOnly) {
  52887. if ($token->equalsAny(['(', ')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE]])) {
  52888. continue;
  52889. }
  52890. return false;
  52891. }
  52892. if ($token->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  52893. $expectArrayOnly = true;
  52894. continue;
  52895. }
  52896. if ($expectNumberOnly && !$token->isGivenKind([T_LNUMBER, T_DNUMBER])) {
  52897. return false;
  52898. }
  52899. if ($token->equals('-')) {
  52900. $expectNumberOnly = true;
  52901. continue;
  52902. }
  52903. if (
  52904. $token->isGivenKind([T_LNUMBER, T_DNUMBER, T_CONSTANT_ENCAPSED_STRING])
  52905. || $token->equalsAny([[T_STRING, 'true'], [T_STRING, 'false'], [T_STRING, 'null']])
  52906. ) {
  52907. $expectNothing = true;
  52908. continue;
  52909. }
  52910. return false;
  52911. }
  52912. return true;
  52913. }
  52914. private function resolveConfiguration(): void
  52915. {
  52916. $candidateTypes = [];
  52917. $this->candidatesMap = [];
  52918. if (null !== $this->configuration['equal']) {
  52919. $candidateTypes[T_IS_EQUAL] = $this->configuration['equal'];
  52920. $candidateTypes[T_IS_NOT_EQUAL] = $this->configuration['equal'];
  52921. }
  52922. if (null !== $this->configuration['identical']) {
  52923. $candidateTypes[T_IS_IDENTICAL] = $this->configuration['identical'];
  52924. $candidateTypes[T_IS_NOT_IDENTICAL] = $this->configuration['identical'];
  52925. }
  52926. if (null !== $this->configuration['less_and_greater']) {
  52927. $candidateTypes[T_IS_SMALLER_OR_EQUAL] = $this->configuration['less_and_greater'];
  52928. $this->candidatesMap[T_IS_SMALLER_OR_EQUAL] = new Token([T_IS_GREATER_OR_EQUAL, '>=']);
  52929. $candidateTypes[T_IS_GREATER_OR_EQUAL] = $this->configuration['less_and_greater'];
  52930. $this->candidatesMap[T_IS_GREATER_OR_EQUAL] = new Token([T_IS_SMALLER_OR_EQUAL, '<=']);
  52931. $candidateTypes['<'] = $this->configuration['less_and_greater'];
  52932. $this->candidatesMap['<'] = new Token('>');
  52933. $candidateTypes['>'] = $this->configuration['less_and_greater'];
  52934. $this->candidatesMap['>'] = new Token('<');
  52935. }
  52936. $this->candidateTypesConfiguration = $candidateTypes;
  52937. $this->candidateTypes = array_keys($candidateTypes);
  52938. }
  52939. }
  52940. <?php
  52941. declare(strict_types=1);
  52942. namespace PhpCsFixer\Fixer\ControlStructure;
  52943. use PhpCsFixer\AbstractFixer;
  52944. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  52945. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  52946. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  52947. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  52948. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  52949. use PhpCsFixer\FixerDefinition\CodeSample;
  52950. use PhpCsFixer\FixerDefinition\FixerDefinition;
  52951. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  52952. use PhpCsFixer\Tokenizer\Token;
  52953. use PhpCsFixer\Tokenizer\Tokens;
  52954. /**
  52955. @phpstan-type
  52956. @phpstan-type
  52957. @implements
  52958. */
  52959. final class EmptyLoopConditionFixer extends AbstractFixer implements ConfigurableFixerInterface
  52960. {
  52961. /**
  52962. @use */
  52963. use ConfigurableFixerTrait;
  52964. private const STYLE_FOR = 'for';
  52965. private const STYLE_WHILE = 'while';
  52966. private const TOKEN_LOOP_KINDS = [T_FOR, T_WHILE];
  52967. public function getDefinition(): FixerDefinitionInterface
  52968. {
  52969. return new FixerDefinition(
  52970. 'Empty loop-condition must be in configured style.',
  52971. [
  52972. new CodeSample("<?php\nfor(;;) {\n foo();\n}\n\ndo {\n foo();\n} while(true); // do while\n"),
  52973. new CodeSample("<?php\nwhile(true) {\n foo();\n}\n", ['style' => self::STYLE_FOR]),
  52974. ]
  52975. );
  52976. }
  52977. public function getPriority(): int
  52978. {
  52979. return 1;
  52980. }
  52981. public function isCandidate(Tokens $tokens): bool
  52982. {
  52983. return $tokens->isAnyTokenKindsFound(self::TOKEN_LOOP_KINDS);
  52984. }
  52985. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  52986. {
  52987. if (self::STYLE_WHILE === $this->configuration['style']) {
  52988. $candidateLoopKinds = [T_FOR, T_WHILE];
  52989. $replacement = [new Token([T_WHILE, 'while']), new Token([T_WHITESPACE, ' ']), new Token('('), new Token([T_STRING, 'true']), new Token(')')];
  52990. $fixLoop = static function (int $index, int $openIndex, int $endIndex) use ($tokens, $replacement): void {
  52991. if (self::isForLoopWithEmptyCondition($tokens, $index, $openIndex, $endIndex)) {
  52992. self::clearNotCommentsInRange($tokens, $index, $endIndex);
  52993. self::cloneAndInsert($tokens, $index, $replacement);
  52994. } elseif (self::isWhileLoopWithEmptyCondition($tokens, $index, $openIndex, $endIndex)) {
  52995. $doIndex = self::getDoIndex($tokens, $index);
  52996. if (null !== $doIndex) {
  52997. self::clearNotCommentsInRange($tokens, $index, $tokens->getNextMeaningfulToken($endIndex));
  52998. $tokens->clearAt($doIndex);
  52999. self::cloneAndInsert($tokens, $doIndex, $replacement);
  53000. }
  53001. }
  53002. };
  53003. } else {
  53004. $candidateLoopKinds = [T_WHILE];
  53005. $replacement = [new Token([T_FOR, 'for']), new Token('('), new Token(';'), new Token(';'), new Token(')')];
  53006. $fixLoop = static function (int $index, int $openIndex, int $endIndex) use ($tokens, $replacement): void {
  53007. if (!self::isWhileLoopWithEmptyCondition($tokens, $index, $openIndex, $endIndex)) {
  53008. return;
  53009. }
  53010. $doIndex = self::getDoIndex($tokens, $index);
  53011. if (null === $doIndex) {
  53012. self::clearNotCommentsInRange($tokens, $index, $endIndex);
  53013. self::cloneAndInsert($tokens, $index, $replacement);
  53014. } else {
  53015. self::clearNotCommentsInRange($tokens, $index, $tokens->getNextMeaningfulToken($endIndex));
  53016. $tokens->clearAt($doIndex);
  53017. self::cloneAndInsert($tokens, $doIndex, $replacement);
  53018. }
  53019. };
  53020. }
  53021. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  53022. if ($tokens[$index]->isGivenKind($candidateLoopKinds)) {
  53023. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  53024. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  53025. $fixLoop($index, $openIndex, $endIndex);
  53026. }
  53027. }
  53028. }
  53029. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  53030. {
  53031. return new FixerConfigurationResolver([
  53032. (new FixerOptionBuilder('style', 'Style of empty loop-condition.'))
  53033. ->setAllowedTypes(['string'])
  53034. ->setAllowedValues([self::STYLE_WHILE, self::STYLE_FOR])
  53035. ->setDefault(self::STYLE_WHILE)
  53036. ->getOption(),
  53037. ]);
  53038. }
  53039. private static function clearNotCommentsInRange(Tokens $tokens, int $indexStart, int $indexEnd): void
  53040. {
  53041. for ($i = $indexStart; $i <= $indexEnd; ++$i) {
  53042. if (!$tokens[$i]->isComment()) {
  53043. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  53044. }
  53045. }
  53046. }
  53047. private static function cloneAndInsert(Tokens $tokens, int $index, array $replacement): void
  53048. {
  53049. $replacementClones = [];
  53050. foreach ($replacement as $token) {
  53051. $replacementClones[] = clone $token;
  53052. }
  53053. $tokens->insertAt($index, $replacementClones);
  53054. }
  53055. private static function getDoIndex(Tokens $tokens, int $index): ?int
  53056. {
  53057. $endIndex = $tokens->getPrevMeaningfulToken($index);
  53058. if (!$tokens[$endIndex]->equals('}')) {
  53059. return null;
  53060. }
  53061. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $endIndex);
  53062. $index = $tokens->getPrevMeaningfulToken($startIndex);
  53063. return null === $index || !$tokens[$index]->isGivenKind(T_DO) ? null : $index;
  53064. }
  53065. private static function isForLoopWithEmptyCondition(Tokens $tokens, int $index, int $openIndex, int $endIndex): bool
  53066. {
  53067. if (!$tokens[$index]->isGivenKind(T_FOR)) {
  53068. return false;
  53069. }
  53070. $index = $tokens->getNextMeaningfulToken($openIndex);
  53071. if (null === $index || !$tokens[$index]->equals(';')) {
  53072. return false;
  53073. }
  53074. $index = $tokens->getNextMeaningfulToken($index);
  53075. return null !== $index && $tokens[$index]->equals(';') && $endIndex === $tokens->getNextMeaningfulToken($index);
  53076. }
  53077. private static function isWhileLoopWithEmptyCondition(Tokens $tokens, int $index, int $openIndex, int $endIndex): bool
  53078. {
  53079. if (!$tokens[$index]->isGivenKind(T_WHILE)) {
  53080. return false;
  53081. }
  53082. $index = $tokens->getNextMeaningfulToken($openIndex);
  53083. return null !== $index && $tokens[$index]->equals([T_STRING, 'true']) && $endIndex === $tokens->getNextMeaningfulToken($index);
  53084. }
  53085. }
  53086. <?php
  53087. declare(strict_types=1);
  53088. namespace PhpCsFixer\Fixer\ControlStructure;
  53089. use PhpCsFixer\AbstractFixer;
  53090. use PhpCsFixer\FixerDefinition\CodeSample;
  53091. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53092. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53093. use PhpCsFixer\Tokenizer\Analyzer\Analysis\SwitchAnalysis;
  53094. use PhpCsFixer\Tokenizer\Analyzer\ControlCaseStructuresAnalyzer;
  53095. use PhpCsFixer\Tokenizer\Token;
  53096. use PhpCsFixer\Tokenizer\Tokens;
  53097. final class SwitchCaseSemicolonToColonFixer extends AbstractFixer
  53098. {
  53099. public function getDefinition(): FixerDefinitionInterface
  53100. {
  53101. return new FixerDefinition(
  53102. 'A case should be followed by a colon and not a semicolon.',
  53103. [
  53104. new CodeSample(
  53105. '<?php
  53106. switch ($a) {
  53107. case 1;
  53108. break;
  53109. default;
  53110. break;
  53111. }
  53112. '
  53113. ),
  53114. ]
  53115. );
  53116. }
  53117. public function getPriority(): int
  53118. {
  53119. return 0;
  53120. }
  53121. public function isCandidate(Tokens $tokens): bool
  53122. {
  53123. return $tokens->isTokenKindFound(T_SWITCH);
  53124. }
  53125. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53126. {
  53127. foreach (ControlCaseStructuresAnalyzer::findControlStructures($tokens, [T_SWITCH]) as $analysis) {
  53128. $default = $analysis->getDefaultAnalysis();
  53129. if (null !== $default) {
  53130. $this->fixTokenIfNeeded($tokens, $default->getColonIndex());
  53131. }
  53132. foreach ($analysis->getCases() as $caseAnalysis) {
  53133. $this->fixTokenIfNeeded($tokens, $caseAnalysis->getColonIndex());
  53134. }
  53135. }
  53136. }
  53137. private function fixTokenIfNeeded(Tokens $tokens, int $index): void
  53138. {
  53139. if ($tokens[$index]->equals(';')) {
  53140. $tokens[$index] = new Token(':');
  53141. }
  53142. }
  53143. }
  53144. <?php
  53145. declare(strict_types=1);
  53146. namespace PhpCsFixer\Fixer\ControlStructure;
  53147. use PhpCsFixer\AbstractFixer;
  53148. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  53149. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  53150. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  53151. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  53152. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  53153. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  53154. use PhpCsFixer\FixerDefinition\CodeSample;
  53155. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53156. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53157. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  53158. use PhpCsFixer\Tokenizer\Tokens;
  53159. /**
  53160. @phpstan-type
  53161. @phpstan-type
  53162. @implements
  53163. */
  53164. final class ControlStructureContinuationPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  53165. {
  53166. /**
  53167. @use */
  53168. use ConfigurableFixerTrait;
  53169. public const NEXT_LINE = 'next_line';
  53170. public const SAME_LINE = 'same_line';
  53171. private const CONTROL_CONTINUATION_TOKENS = [
  53172. T_CATCH,
  53173. T_ELSE,
  53174. T_ELSEIF,
  53175. T_FINALLY,
  53176. T_WHILE,
  53177. ];
  53178. public function getDefinition(): FixerDefinitionInterface
  53179. {
  53180. return new FixerDefinition(
  53181. 'Control structure continuation keyword must be on the configured line.',
  53182. [
  53183. new CodeSample(
  53184. '<?php
  53185. if ($baz == true) {
  53186. echo "foo";
  53187. }
  53188. else {
  53189. echo "bar";
  53190. }
  53191. '
  53192. ),
  53193. new CodeSample(
  53194. '<?php
  53195. if ($baz == true) {
  53196. echo "foo";
  53197. } else {
  53198. echo "bar";
  53199. }
  53200. ',
  53201. ['position' => self::NEXT_LINE]
  53202. ),
  53203. ]
  53204. );
  53205. }
  53206. public function isCandidate(Tokens $tokens): bool
  53207. {
  53208. return $tokens->isAnyTokenKindsFound(self::CONTROL_CONTINUATION_TOKENS);
  53209. }
  53210. public function getPriority(): int
  53211. {
  53212. return parent::getPriority();
  53213. }
  53214. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  53215. {
  53216. return new FixerConfigurationResolver([
  53217. (new FixerOptionBuilder('position', 'The position of the keyword that continues the control structure.'))
  53218. ->setAllowedValues([self::NEXT_LINE, self::SAME_LINE])
  53219. ->setDefault(self::SAME_LINE)
  53220. ->getOption(),
  53221. ]);
  53222. }
  53223. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53224. {
  53225. $this->fixControlContinuationBraces($tokens);
  53226. }
  53227. private function fixControlContinuationBraces(Tokens $tokens): void
  53228. {
  53229. for ($index = \count($tokens) - 1; 0 < $index; --$index) {
  53230. $token = $tokens[$index];
  53231. if (!$token->isGivenKind(self::CONTROL_CONTINUATION_TOKENS)) {
  53232. continue;
  53233. }
  53234. $prevIndex = $tokens->getPrevNonWhitespace($index);
  53235. $prevToken = $tokens[$prevIndex];
  53236. if (!$prevToken->equals('}')) {
  53237. continue;
  53238. }
  53239. if ($token->isGivenKind(T_WHILE)) {
  53240. $prevIndex = $tokens->getPrevMeaningfulToken(
  53241. $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $prevIndex)
  53242. );
  53243. if (!$tokens[$prevIndex]->isGivenKind(T_DO)) {
  53244. continue;
  53245. }
  53246. }
  53247. $tokens->ensureWhitespaceAtIndex(
  53248. $index - 1,
  53249. 1,
  53250. self::NEXT_LINE === $this->configuration['position']
  53251. ? $this->whitespacesConfig->getLineEnding().WhitespacesAnalyzer::detectIndent($tokens, $index)
  53252. : ' '
  53253. );
  53254. }
  53255. }
  53256. }
  53257. <?php
  53258. declare(strict_types=1);
  53259. namespace PhpCsFixer\Fixer\ControlStructure;
  53260. use PhpCsFixer\AbstractNoUselessElseFixer;
  53261. use PhpCsFixer\FixerDefinition\CodeSample;
  53262. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53263. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53264. use PhpCsFixer\Preg;
  53265. use PhpCsFixer\Tokenizer\Token;
  53266. use PhpCsFixer\Tokenizer\Tokens;
  53267. final class NoSuperfluousElseifFixer extends AbstractNoUselessElseFixer
  53268. {
  53269. public function isCandidate(Tokens $tokens): bool
  53270. {
  53271. return $tokens->isAnyTokenKindsFound([T_ELSE, T_ELSEIF]);
  53272. }
  53273. public function getDefinition(): FixerDefinitionInterface
  53274. {
  53275. return new FixerDefinition(
  53276. 'Replaces superfluous `elseif` with `if`.',
  53277. [
  53278. new CodeSample("<?php\nif (\$a) {\n return 1;\n} elseif (\$b) {\n return 2;\n}\n"),
  53279. ]
  53280. );
  53281. }
  53282. public function getPriority(): int
  53283. {
  53284. return parent::getPriority();
  53285. }
  53286. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53287. {
  53288. foreach ($tokens as $index => $token) {
  53289. if ($this->isElseif($tokens, $index) && $this->isSuperfluousElse($tokens, $index)) {
  53290. $this->convertElseifToIf($tokens, $index);
  53291. }
  53292. }
  53293. }
  53294. private function isElseif(Tokens $tokens, int $index): bool
  53295. {
  53296. return
  53297. $tokens[$index]->isGivenKind(T_ELSEIF)
  53298. || ($tokens[$index]->isGivenKind(T_ELSE) && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_IF));
  53299. }
  53300. private function convertElseifToIf(Tokens $tokens, int $index): void
  53301. {
  53302. if ($tokens[$index]->isGivenKind(T_ELSE)) {
  53303. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  53304. } else {
  53305. $tokens[$index] = new Token([T_IF, 'if']);
  53306. }
  53307. $whitespace = '';
  53308. for ($previous = $index - 1; $previous > 0; --$previous) {
  53309. $token = $tokens[$previous];
  53310. if ($token->isWhitespace() && Preg::match('/(\R\N*)$/', $token->getContent(), $matches)) {
  53311. $whitespace = $matches[1];
  53312. break;
  53313. }
  53314. }
  53315. if ('' === $whitespace) {
  53316. return;
  53317. }
  53318. $previousToken = $tokens[$index - 1];
  53319. if (!$previousToken->isWhitespace()) {
  53320. $tokens->insertAt($index, new Token([T_WHITESPACE, $whitespace]));
  53321. } elseif (!Preg::match('/\R/', $previousToken->getContent())) {
  53322. $tokens[$index - 1] = new Token([T_WHITESPACE, $whitespace]);
  53323. }
  53324. }
  53325. }
  53326. <?php
  53327. declare(strict_types=1);
  53328. namespace PhpCsFixer\Fixer\ControlStructure;
  53329. use PhpCsFixer\AbstractFixer;
  53330. use PhpCsFixer\FixerDefinition\CodeSample;
  53331. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53332. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53333. use PhpCsFixer\Tokenizer\Analyzer\Analysis\SwitchAnalysis;
  53334. use PhpCsFixer\Tokenizer\Analyzer\ControlCaseStructuresAnalyzer;
  53335. use PhpCsFixer\Tokenizer\Tokens;
  53336. final class SwitchCaseSpaceFixer extends AbstractFixer
  53337. {
  53338. public function getDefinition(): FixerDefinitionInterface
  53339. {
  53340. return new FixerDefinition(
  53341. 'Removes extra spaces between colon and case value.',
  53342. [
  53343. new CodeSample(
  53344. '<?php
  53345. switch($a) {
  53346. case 1 :
  53347. break;
  53348. default :
  53349. return 2;
  53350. }
  53351. '
  53352. ),
  53353. ]
  53354. );
  53355. }
  53356. public function isCandidate(Tokens $tokens): bool
  53357. {
  53358. return $tokens->isTokenKindFound(T_SWITCH);
  53359. }
  53360. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53361. {
  53362. foreach (ControlCaseStructuresAnalyzer::findControlStructures($tokens, [T_SWITCH]) as $analysis) {
  53363. $default = $analysis->getDefaultAnalysis();
  53364. if (null !== $default) {
  53365. $index = $default->getIndex();
  53366. if (!$tokens[$index + 1]->isWhitespace() || !$tokens[$index + 2]->equalsAny([':', ';'])) {
  53367. continue;
  53368. }
  53369. $tokens->clearAt($index + 1);
  53370. }
  53371. foreach ($analysis->getCases() as $caseAnalysis) {
  53372. $colonIndex = $caseAnalysis->getColonIndex();
  53373. $valueIndex = $tokens->getPrevNonWhitespace($colonIndex);
  53374. if ($valueIndex === $colonIndex - 1 || $tokens[$valueIndex]->isComment()) {
  53375. continue;
  53376. }
  53377. $tokens->clearAt($valueIndex + 1);
  53378. }
  53379. }
  53380. }
  53381. }
  53382. <?php
  53383. declare(strict_types=1);
  53384. namespace PhpCsFixer\Fixer\ControlStructure;
  53385. use PhpCsFixer\AbstractFixer;
  53386. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  53387. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  53388. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  53389. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  53390. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  53391. use PhpCsFixer\FixerDefinition\CodeSample;
  53392. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53393. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53394. use PhpCsFixer\Tokenizer\Token;
  53395. use PhpCsFixer\Tokenizer\Tokens;
  53396. /**
  53397. @phpstan-type
  53398. @phpstan-type
  53399. @implements
  53400. */
  53401. final class NoUnneededBracesFixer extends AbstractFixer implements ConfigurableFixerInterface
  53402. {
  53403. /**
  53404. @use */
  53405. use ConfigurableFixerTrait;
  53406. public function getDefinition(): FixerDefinitionInterface
  53407. {
  53408. return new FixerDefinition(
  53409. 'Removes unneeded braces that are superfluous and aren\'t part of a control structure\'s body.',
  53410. [
  53411. new CodeSample(
  53412. '<?php {
  53413. echo 1;
  53414. }
  53415. switch ($b) {
  53416. case 1: {
  53417. break;
  53418. }
  53419. }
  53420. '
  53421. ),
  53422. new CodeSample(
  53423. '<?php
  53424. namespace Foo {
  53425. function Bar(){}
  53426. }
  53427. ',
  53428. ['namespaces' => true]
  53429. ),
  53430. ]
  53431. );
  53432. }
  53433. public function getPriority(): int
  53434. {
  53435. return 40;
  53436. }
  53437. public function isCandidate(Tokens $tokens): bool
  53438. {
  53439. return $tokens->isTokenKindFound('}');
  53440. }
  53441. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53442. {
  53443. foreach ($this->findBraceOpen($tokens) as $index) {
  53444. if ($this->isOverComplete($tokens, $index)) {
  53445. $this->clearOverCompleteBraces($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
  53446. }
  53447. }
  53448. if (true === $this->configuration['namespaces']) {
  53449. $this->clearIfIsOverCompleteNamespaceBlock($tokens);
  53450. }
  53451. }
  53452. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  53453. {
  53454. return new FixerConfigurationResolver([
  53455. (new FixerOptionBuilder('namespaces', 'Remove unneeded braces from bracketed namespaces.'))
  53456. ->setAllowedTypes(['bool'])
  53457. ->setDefault(false)
  53458. ->getOption(),
  53459. ]);
  53460. }
  53461. private function clearOverCompleteBraces(Tokens $tokens, int $openIndex, int $closeIndex): void
  53462. {
  53463. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  53464. $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
  53465. }
  53466. private function findBraceOpen(Tokens $tokens): iterable
  53467. {
  53468. for ($i = \count($tokens) - 1; $i > 0; --$i) {
  53469. if ($tokens[$i]->equals('{')) {
  53470. yield $i;
  53471. }
  53472. }
  53473. }
  53474. private function isOverComplete(Tokens $tokens, int $index): bool
  53475. {
  53476. static $include = ['{', '}', [T_OPEN_TAG], ':', ';'];
  53477. return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny($include);
  53478. }
  53479. private function clearIfIsOverCompleteNamespaceBlock(Tokens $tokens): void
  53480. {
  53481. if (1 !== $tokens->countTokenKind(T_NAMESPACE)) {
  53482. return;
  53483. }
  53484. $index = $tokens->getNextTokenOfKind(0, [[T_NAMESPACE]]);
  53485. $namespaceIsNamed = false;
  53486. $index = $tokens->getNextMeaningfulToken($index);
  53487. while ($tokens[$index]->isGivenKind([T_STRING, T_NS_SEPARATOR])) {
  53488. $index = $tokens->getNextMeaningfulToken($index);
  53489. $namespaceIsNamed = true;
  53490. }
  53491. if (!$namespaceIsNamed) {
  53492. return;
  53493. }
  53494. if (!$tokens[$index]->equals('{')) {
  53495. return;
  53496. }
  53497. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  53498. $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
  53499. if (null !== $afterCloseIndex && (!$tokens[$afterCloseIndex]->isGivenKind(T_CLOSE_TAG) || null !== $tokens->getNextMeaningfulToken($afterCloseIndex))) {
  53500. return;
  53501. }
  53502. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  53503. $tokens[$index] = new Token(';');
  53504. if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
  53505. $tokens->clearTokenAndMergeSurroundingWhitespace($index - 1);
  53506. }
  53507. }
  53508. }
  53509. <?php
  53510. declare(strict_types=1);
  53511. namespace PhpCsFixer\Fixer\ControlStructure;
  53512. use PhpCsFixer\AbstractFixer;
  53513. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  53514. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  53515. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  53516. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  53517. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  53518. use PhpCsFixer\FixerDefinition\CodeSample;
  53519. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53520. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53521. use PhpCsFixer\Tokenizer\Token;
  53522. use PhpCsFixer\Tokenizer\Tokens;
  53523. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  53524. /**
  53525. @phpstan-type
  53526. @phpstan-type
  53527. @implements
  53528. */
  53529. final class EmptyLoopBodyFixer extends AbstractFixer implements ConfigurableFixerInterface
  53530. {
  53531. /**
  53532. @use */
  53533. use ConfigurableFixerTrait;
  53534. private const STYLE_BRACES = 'braces';
  53535. private const STYLE_SEMICOLON = 'semicolon';
  53536. private const TOKEN_LOOP_KINDS = [T_FOR, T_FOREACH, T_WHILE];
  53537. public function getDefinition(): FixerDefinitionInterface
  53538. {
  53539. return new FixerDefinition(
  53540. 'Empty loop-body must be in configured style.',
  53541. [
  53542. new CodeSample("<?php while(foo()){}\n"),
  53543. new CodeSample(
  53544. "<?php while(foo());\n",
  53545. [
  53546. 'style' => self::STYLE_BRACES,
  53547. ]
  53548. ),
  53549. ]
  53550. );
  53551. }
  53552. public function getPriority(): int
  53553. {
  53554. return 39;
  53555. }
  53556. public function isCandidate(Tokens $tokens): bool
  53557. {
  53558. return $tokens->isAnyTokenKindsFound(self::TOKEN_LOOP_KINDS);
  53559. }
  53560. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53561. {
  53562. if (self::STYLE_BRACES === $this->configuration['style']) {
  53563. $analyzer = new TokensAnalyzer($tokens);
  53564. $fixLoop = static function (int $index, int $endIndex) use ($tokens, $analyzer): void {
  53565. if ($tokens[$index]->isGivenKind(T_WHILE) && $analyzer->isWhilePartOfDoWhile($index)) {
  53566. return;
  53567. }
  53568. $semiColonIndex = $tokens->getNextMeaningfulToken($endIndex);
  53569. if (!$tokens[$semiColonIndex]->equals(';')) {
  53570. return;
  53571. }
  53572. $tokens[$semiColonIndex] = new Token('{');
  53573. $tokens->insertAt($semiColonIndex + 1, new Token('}'));
  53574. };
  53575. } else {
  53576. $fixLoop = static function (int $index, int $endIndex) use ($tokens): void {
  53577. $braceOpenIndex = $tokens->getNextMeaningfulToken($endIndex);
  53578. if (!$tokens[$braceOpenIndex]->equals('{')) {
  53579. return;
  53580. }
  53581. $braceCloseIndex = $tokens->getNextNonWhitespace($braceOpenIndex);
  53582. if (!$tokens[$braceCloseIndex]->equals('}')) {
  53583. return;
  53584. }
  53585. $tokens[$braceOpenIndex] = new Token(';');
  53586. $tokens->clearTokenAndMergeSurroundingWhitespace($braceCloseIndex);
  53587. };
  53588. }
  53589. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  53590. if ($tokens[$index]->isGivenKind(self::TOKEN_LOOP_KINDS)) {
  53591. $endIndex = $tokens->getNextTokenOfKind($index, ['(']);
  53592. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex);
  53593. $fixLoop($index, $endIndex);
  53594. }
  53595. }
  53596. }
  53597. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  53598. {
  53599. return new FixerConfigurationResolver([
  53600. (new FixerOptionBuilder('style', 'Style of empty loop-bodies.'))
  53601. ->setAllowedTypes(['string'])
  53602. ->setAllowedValues([self::STYLE_BRACES, self::STYLE_SEMICOLON])
  53603. ->setDefault(self::STYLE_SEMICOLON)
  53604. ->getOption(),
  53605. ]);
  53606. }
  53607. }
  53608. <?php
  53609. declare(strict_types=1);
  53610. namespace PhpCsFixer\Fixer\ControlStructure;
  53611. use PhpCsFixer\AbstractFixer;
  53612. use PhpCsFixer\FixerDefinition\CodeSample;
  53613. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53614. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53615. use PhpCsFixer\Preg;
  53616. use PhpCsFixer\Tokenizer\Token;
  53617. use PhpCsFixer\Tokenizer\Tokens;
  53618. final class SwitchContinueToBreakFixer extends AbstractFixer
  53619. {
  53620. private array $switchLevels = [];
  53621. public function getDefinition(): FixerDefinitionInterface
  53622. {
  53623. return new FixerDefinition(
  53624. 'Switch case must not be ended with `continue` but with `break`.',
  53625. [
  53626. new CodeSample(
  53627. '<?php
  53628. switch ($foo) {
  53629. case 1:
  53630. continue;
  53631. }
  53632. '
  53633. ),
  53634. new CodeSample(
  53635. '<?php
  53636. switch ($foo) {
  53637. case 1:
  53638. while($bar) {
  53639. do {
  53640. continue 3;
  53641. } while(false);
  53642. if ($foo + 1 > 3) {
  53643. continue;
  53644. }
  53645. continue 2;
  53646. }
  53647. }
  53648. '
  53649. ),
  53650. ]
  53651. );
  53652. }
  53653. public function getPriority(): int
  53654. {
  53655. return 0;
  53656. }
  53657. public function isCandidate(Tokens $tokens): bool
  53658. {
  53659. return $tokens->isAllTokenKindsFound([T_SWITCH, T_CONTINUE]) && !$tokens->hasAlternativeSyntax();
  53660. }
  53661. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53662. {
  53663. $count = \count($tokens);
  53664. for ($index = 1; $index < $count - 1; ++$index) {
  53665. $index = $this->doFix($tokens, $index, 0, false);
  53666. }
  53667. }
  53668. private function doFix(Tokens $tokens, int $index, int $depth, bool $isInSwitch): int
  53669. {
  53670. $token = $tokens[$index];
  53671. if ($token->isGivenKind([T_FOREACH, T_FOR, T_WHILE])) {
  53672. $index = $tokens->getNextTokenOfKind($index, ['(']);
  53673. $index = $tokens->getNextTokenOfKind($index, [')']);
  53674. $index = $tokens->getNextTokenOfKind($index, ['{', ';', [T_CLOSE_TAG]]);
  53675. if (!$tokens[$index]->equals('{')) {
  53676. return $index;
  53677. }
  53678. return $this->fixInLoop($tokens, $index, $depth + 1);
  53679. }
  53680. if ($token->isGivenKind(T_DO)) {
  53681. return $this->fixInLoop($tokens, $tokens->getNextTokenOfKind($index, ['{']), $depth + 1);
  53682. }
  53683. if ($token->isGivenKind(T_SWITCH)) {
  53684. return $this->fixInSwitch($tokens, $index, $depth + 1);
  53685. }
  53686. if ($token->isGivenKind(T_CONTINUE)) {
  53687. return $this->fixContinueWhenActsAsBreak($tokens, $index, $isInSwitch, $depth);
  53688. }
  53689. return $index;
  53690. }
  53691. private function fixInSwitch(Tokens $tokens, int $switchIndex, int $depth): int
  53692. {
  53693. $this->switchLevels[] = $depth;
  53694. $openIndex = $tokens->getNextTokenOfKind($switchIndex, ['{']);
  53695. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex);
  53696. for ($index = $openIndex + 1; $index < $closeIndex; ++$index) {
  53697. $index = $this->doFix($tokens, $index, $depth, true);
  53698. }
  53699. array_pop($this->switchLevels);
  53700. return $closeIndex;
  53701. }
  53702. private function fixInLoop(Tokens $tokens, int $openIndex, int $depth): int
  53703. {
  53704. $openCount = 1;
  53705. while (true) {
  53706. ++$openIndex;
  53707. $token = $tokens[$openIndex];
  53708. if ($token->equals('{')) {
  53709. ++$openCount;
  53710. continue;
  53711. }
  53712. if ($token->equals('}')) {
  53713. --$openCount;
  53714. if (0 === $openCount) {
  53715. break;
  53716. }
  53717. continue;
  53718. }
  53719. $openIndex = $this->doFix($tokens, $openIndex, $depth, false);
  53720. }
  53721. return $openIndex;
  53722. }
  53723. private function fixContinueWhenActsAsBreak(Tokens $tokens, int $continueIndex, bool $isInSwitch, int $depth): int
  53724. {
  53725. $followingContinueIndex = $tokens->getNextMeaningfulToken($continueIndex);
  53726. $followingContinueToken = $tokens[$followingContinueIndex];
  53727. if ($isInSwitch && $followingContinueToken->equals(';')) {
  53728. $this->replaceContinueWithBreakToken($tokens, $continueIndex);
  53729. return $followingContinueIndex;
  53730. }
  53731. if (!$followingContinueToken->isGivenKind(T_LNUMBER)) {
  53732. return $followingContinueIndex;
  53733. }
  53734. $afterFollowingContinueIndex = $tokens->getNextMeaningfulToken($followingContinueIndex);
  53735. if (!$tokens[$afterFollowingContinueIndex]->equals(';')) {
  53736. return $afterFollowingContinueIndex;
  53737. }
  53738. $jump = $followingContinueToken->getContent();
  53739. $jump = str_replace('_', '', $jump);
  53740. if (\strlen($jump) > 2 && 'x' === $jump[1]) {
  53741. $jump = hexdec($jump);
  53742. } elseif (\strlen($jump) > 2 && 'b' === $jump[1]) {
  53743. $jump = bindec($jump);
  53744. } elseif (\strlen($jump) > 1 && '0' === $jump[0]) {
  53745. $jump = octdec($jump);
  53746. } elseif (Preg::match('#^\d+$#', $jump)) {
  53747. $jump = (float) $jump;
  53748. } else {
  53749. return $afterFollowingContinueIndex;
  53750. }
  53751. if ($jump > PHP_INT_MAX) {
  53752. return $afterFollowingContinueIndex;
  53753. }
  53754. $jump = (int) $jump;
  53755. if ($isInSwitch && (1 === $jump || 0 === $jump)) {
  53756. $this->replaceContinueWithBreakToken($tokens, $continueIndex);
  53757. return $afterFollowingContinueIndex;
  53758. }
  53759. $jumpDestination = $depth - $jump + 1;
  53760. if (\in_array($jumpDestination, $this->switchLevels, true)) {
  53761. $this->replaceContinueWithBreakToken($tokens, $continueIndex);
  53762. return $afterFollowingContinueIndex;
  53763. }
  53764. return $afterFollowingContinueIndex;
  53765. }
  53766. private function replaceContinueWithBreakToken(Tokens $tokens, int $index): void
  53767. {
  53768. $tokens[$index] = new Token([T_BREAK, 'break']);
  53769. }
  53770. }
  53771. <?php
  53772. declare(strict_types=1);
  53773. namespace PhpCsFixer\Fixer\ControlStructure;
  53774. use PhpCsFixer\AbstractFixer;
  53775. use PhpCsFixer\FixerDefinition\CodeSample;
  53776. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53777. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53778. use PhpCsFixer\Tokenizer\Token;
  53779. use PhpCsFixer\Tokenizer\Tokens;
  53780. final class SimplifiedIfReturnFixer extends AbstractFixer
  53781. {
  53782. private array $sequences = [
  53783. [
  53784. 'isNegative' => false,
  53785. 'sequence' => [
  53786. '{', [T_RETURN], [T_STRING, 'true'], ';', '}',
  53787. [T_RETURN], [T_STRING, 'false'], ';',
  53788. ],
  53789. ],
  53790. [
  53791. 'isNegative' => true,
  53792. 'sequence' => [
  53793. '{', [T_RETURN], [T_STRING, 'false'], ';', '}',
  53794. [T_RETURN], [T_STRING, 'true'], ';',
  53795. ],
  53796. ],
  53797. [
  53798. 'isNegative' => false,
  53799. 'sequence' => [
  53800. [T_RETURN], [T_STRING, 'true'], ';',
  53801. [T_RETURN], [T_STRING, 'false'], ';',
  53802. ],
  53803. ],
  53804. [
  53805. 'isNegative' => true,
  53806. 'sequence' => [
  53807. [T_RETURN], [T_STRING, 'false'], ';',
  53808. [T_RETURN], [T_STRING, 'true'], ';',
  53809. ],
  53810. ],
  53811. ];
  53812. public function getDefinition(): FixerDefinitionInterface
  53813. {
  53814. return new FixerDefinition(
  53815. 'Simplify `if` control structures that return the boolean result of their condition.',
  53816. [new CodeSample("<?php\nif (\$foo) { return true; } return false;\n")]
  53817. );
  53818. }
  53819. public function getPriority(): int
  53820. {
  53821. return 1;
  53822. }
  53823. public function isCandidate(Tokens $tokens): bool
  53824. {
  53825. return $tokens->isAllTokenKindsFound([T_IF, T_RETURN, T_STRING]);
  53826. }
  53827. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53828. {
  53829. for ($ifIndex = $tokens->count() - 1; 0 <= $ifIndex; --$ifIndex) {
  53830. if (!$tokens[$ifIndex]->isGivenKind([T_IF, T_ELSEIF])) {
  53831. continue;
  53832. }
  53833. if ($tokens[$tokens->getPrevMeaningfulToken($ifIndex)]->equals(')')) {
  53834. continue;
  53835. }
  53836. $startParenthesisIndex = $tokens->getNextTokenOfKind($ifIndex, ['(']);
  53837. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
  53838. $firstCandidateIndex = $tokens->getNextMeaningfulToken($endParenthesisIndex);
  53839. foreach ($this->sequences as $sequenceSpec) {
  53840. $sequenceFound = $tokens->findSequence($sequenceSpec['sequence'], $firstCandidateIndex);
  53841. if (null === $sequenceFound) {
  53842. continue;
  53843. }
  53844. $firstSequenceIndex = array_key_first($sequenceFound);
  53845. if ($firstSequenceIndex !== $firstCandidateIndex) {
  53846. continue;
  53847. }
  53848. $indicesToClear = array_keys($sequenceFound);
  53849. array_pop($indicesToClear);
  53850. rsort($indicesToClear);
  53851. foreach ($indicesToClear as $index) {
  53852. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  53853. }
  53854. $newTokens = [
  53855. new Token([T_RETURN, 'return']),
  53856. new Token([T_WHITESPACE, ' ']),
  53857. ];
  53858. if ($sequenceSpec['isNegative']) {
  53859. $newTokens[] = new Token('!');
  53860. } else {
  53861. $newTokens[] = new Token([T_BOOL_CAST, '(bool)']);
  53862. }
  53863. $tokens->overrideRange($ifIndex, $ifIndex, $newTokens);
  53864. }
  53865. }
  53866. }
  53867. }
  53868. <?php
  53869. declare(strict_types=1);
  53870. namespace PhpCsFixer\Fixer\ControlStructure;
  53871. use PhpCsFixer\AbstractFixer;
  53872. use PhpCsFixer\FixerDefinition\CodeSample;
  53873. use PhpCsFixer\FixerDefinition\FixerDefinition;
  53874. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  53875. use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
  53876. use PhpCsFixer\Tokenizer\Token;
  53877. use PhpCsFixer\Tokenizer\Tokens;
  53878. final class ControlStructureBracesFixer extends AbstractFixer
  53879. {
  53880. public function getDefinition(): FixerDefinitionInterface
  53881. {
  53882. return new FixerDefinition(
  53883. 'The body of each control structure MUST be enclosed within braces.',
  53884. [new CodeSample("<?php\nif (foo()) echo 'Hello!';\n")]
  53885. );
  53886. }
  53887. public function isCandidate(Tokens $tokens): bool
  53888. {
  53889. return true;
  53890. }
  53891. public function getPriority(): int
  53892. {
  53893. return 1;
  53894. }
  53895. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  53896. {
  53897. $alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
  53898. $controlTokens = $this->getControlTokens();
  53899. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  53900. $token = $tokens[$index];
  53901. if (!$token->isGivenKind($controlTokens)) {
  53902. continue;
  53903. }
  53904. if (
  53905. $token->isGivenKind(T_ELSE)
  53906. && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_IF)
  53907. ) {
  53908. continue;
  53909. }
  53910. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  53911. $nextAfterParenthesisEndIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  53912. $tokenAfterParenthesis = $tokens[$nextAfterParenthesisEndIndex];
  53913. if ($tokenAfterParenthesis->equalsAny([';', '{', ':', [T_CLOSE_TAG]])) {
  53914. continue;
  53915. }
  53916. $statementEndIndex = null;
  53917. if ($tokenAfterParenthesis->isGivenKind([T_IF, T_FOR, T_FOREACH, T_SWITCH, T_WHILE])) {
  53918. $tokenAfterParenthesisBlockEnd = $tokens->findBlockEnd(
  53919. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  53920. $tokens->getNextMeaningfulToken($nextAfterParenthesisEndIndex)
  53921. );
  53922. if ($tokens[$tokens->getNextMeaningfulToken($tokenAfterParenthesisBlockEnd)]->equals(':')) {
  53923. $statementEndIndex = $alternativeSyntaxAnalyzer->findAlternativeSyntaxBlockEnd($tokens, $nextAfterParenthesisEndIndex);
  53924. $tokenAfterStatementEndIndex = $tokens->getNextMeaningfulToken($statementEndIndex);
  53925. if ($tokens[$tokenAfterStatementEndIndex]->equals(';')) {
  53926. $statementEndIndex = $tokenAfterStatementEndIndex;
  53927. }
  53928. }
  53929. }
  53930. if (null === $statementEndIndex) {
  53931. $statementEndIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  53932. }
  53933. $tokensToInsertAfterStatement = [
  53934. new Token([T_WHITESPACE, ' ']),
  53935. new Token('}'),
  53936. ];
  53937. if (!$tokens[$statementEndIndex]->equalsAny([';', '}'])) {
  53938. array_unshift($tokensToInsertAfterStatement, new Token(';'));
  53939. }
  53940. $tokens->insertSlices([$statementEndIndex + 1 => $tokensToInsertAfterStatement]);
  53941. $tokens->insertSlices([$parenthesisEndIndex + 1 => [
  53942. new Token([T_WHITESPACE, ' ']),
  53943. new Token('{'),
  53944. ]]);
  53945. }
  53946. }
  53947. private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
  53948. {
  53949. $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
  53950. $nextToken = $tokens[$nextIndex];
  53951. if (!$nextToken->equals('(')) {
  53952. return $structureTokenIndex;
  53953. }
  53954. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  53955. }
  53956. private function findStatementEnd(Tokens $tokens, int $parenthesisEndIndex): int
  53957. {
  53958. $nextIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  53959. if (null === $nextIndex) {
  53960. return $parenthesisEndIndex;
  53961. }
  53962. $nextToken = $tokens[$nextIndex];
  53963. if ($nextToken->equals('{')) {
  53964. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nextIndex);
  53965. }
  53966. if ($nextToken->isGivenKind($this->getControlTokens())) {
  53967. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
  53968. $endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  53969. if ($nextToken->isGivenKind([T_IF, T_TRY, T_DO])) {
  53970. $openingTokenKind = $nextToken->getId();
  53971. while (true) {
  53972. $nextIndex = $tokens->getNextMeaningfulToken($endIndex);
  53973. if (null !== $nextIndex && $tokens[$nextIndex]->isGivenKind($this->getControlContinuationTokensForOpeningToken($openingTokenKind))) {
  53974. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
  53975. $endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
  53976. if ($tokens[$nextIndex]->isGivenKind($this->getFinalControlContinuationTokensForOpeningToken($openingTokenKind))) {
  53977. return $endIndex;
  53978. }
  53979. } else {
  53980. break;
  53981. }
  53982. }
  53983. }
  53984. return $endIndex;
  53985. }
  53986. $index = $parenthesisEndIndex;
  53987. while (true) {
  53988. $token = $tokens[++$index];
  53989. if ($token->equals('{')) {
  53990. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  53991. continue;
  53992. }
  53993. if ($token->equals(';')) {
  53994. return $index;
  53995. }
  53996. if ($token->isGivenKind(T_CLOSE_TAG)) {
  53997. return $tokens->getPrevNonWhitespace($index);
  53998. }
  53999. }
  54000. }
  54001. private function getControlTokens(): array
  54002. {
  54003. static $tokens = [
  54004. T_DECLARE,
  54005. T_DO,
  54006. T_ELSE,
  54007. T_ELSEIF,
  54008. T_FINALLY,
  54009. T_FOR,
  54010. T_FOREACH,
  54011. T_IF,
  54012. T_WHILE,
  54013. T_TRY,
  54014. T_CATCH,
  54015. T_SWITCH,
  54016. ];
  54017. return $tokens;
  54018. }
  54019. private function getControlContinuationTokensForOpeningToken(int $openingTokenKind): array
  54020. {
  54021. if (T_IF === $openingTokenKind) {
  54022. return [
  54023. T_ELSE,
  54024. T_ELSEIF,
  54025. ];
  54026. }
  54027. if (T_DO === $openingTokenKind) {
  54028. return [T_WHILE];
  54029. }
  54030. if (T_TRY === $openingTokenKind) {
  54031. return [
  54032. T_CATCH,
  54033. T_FINALLY,
  54034. ];
  54035. }
  54036. return [];
  54037. }
  54038. private function getFinalControlContinuationTokensForOpeningToken(int $openingTokenKind): array
  54039. {
  54040. if (T_IF === $openingTokenKind) {
  54041. return [T_ELSE];
  54042. }
  54043. if (T_TRY === $openingTokenKind) {
  54044. return [T_FINALLY];
  54045. }
  54046. return [];
  54047. }
  54048. }
  54049. <?php
  54050. declare(strict_types=1);
  54051. namespace PhpCsFixer\Fixer\ControlStructure;
  54052. use PhpCsFixer\AbstractNoUselessElseFixer;
  54053. use PhpCsFixer\FixerDefinition\CodeSample;
  54054. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54055. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54056. use PhpCsFixer\Tokenizer\Tokens;
  54057. final class NoUselessElseFixer extends AbstractNoUselessElseFixer
  54058. {
  54059. public function isCandidate(Tokens $tokens): bool
  54060. {
  54061. return $tokens->isTokenKindFound(T_ELSE);
  54062. }
  54063. public function getDefinition(): FixerDefinitionInterface
  54064. {
  54065. return new FixerDefinition(
  54066. 'There should not be useless `else` cases.',
  54067. [
  54068. new CodeSample("<?php\nif (\$a) {\n return 1;\n} else {\n return 2;\n}\n"),
  54069. ]
  54070. );
  54071. }
  54072. public function getPriority(): int
  54073. {
  54074. return parent::getPriority();
  54075. }
  54076. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  54077. {
  54078. foreach ($tokens as $index => $token) {
  54079. if (!$token->isGivenKind(T_ELSE)) {
  54080. continue;
  54081. }
  54082. if ($tokens[$tokens->getNextMeaningfulToken($index)]->equalsAny([':', [T_IF]])) {
  54083. continue;
  54084. }
  54085. $this->fixEmptyElse($tokens, $index);
  54086. if ($tokens->isEmptyAt($index)) {
  54087. continue;
  54088. }
  54089. if ($this->isSuperfluousElse($tokens, $index)) {
  54090. $this->clearElse($tokens, $index);
  54091. }
  54092. }
  54093. }
  54094. private function fixEmptyElse(Tokens $tokens, int $index): void
  54095. {
  54096. $next = $tokens->getNextMeaningfulToken($index);
  54097. if ($tokens[$next]->equals('{')) {
  54098. $close = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next);
  54099. if (1 === $close - $next) {
  54100. $this->clearElse($tokens, $index);
  54101. } elseif ($tokens->getNextMeaningfulToken($next) === $close) {
  54102. $this->clearElse($tokens, $index);
  54103. }
  54104. return;
  54105. }
  54106. $end = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  54107. if ($next === $end) {
  54108. $this->clearElse($tokens, $index);
  54109. }
  54110. }
  54111. private function clearElse(Tokens $tokens, int $index): void
  54112. {
  54113. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  54114. $next = $tokens->getNextMeaningfulToken($index);
  54115. if (!$tokens[$next]->equals('{')) {
  54116. return;
  54117. }
  54118. $tokens->clearTokenAndMergeSurroundingWhitespace($tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next));
  54119. $tokens->clearTokenAndMergeSurroundingWhitespace($next);
  54120. }
  54121. }
  54122. <?php
  54123. declare(strict_types=1);
  54124. namespace PhpCsFixer\Fixer\ControlStructure;
  54125. use PhpCsFixer\AbstractFixer;
  54126. use PhpCsFixer\FixerDefinition\CodeSample;
  54127. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54128. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54129. use PhpCsFixer\Tokenizer\Token;
  54130. use PhpCsFixer\Tokenizer\Tokens;
  54131. final class ElseifFixer extends AbstractFixer
  54132. {
  54133. public function getDefinition(): FixerDefinitionInterface
  54134. {
  54135. return new FixerDefinition(
  54136. 'The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words.',
  54137. [new CodeSample("<?php\nif (\$a) {\n} else if (\$b) {\n}\n")]
  54138. );
  54139. }
  54140. public function getPriority(): int
  54141. {
  54142. return 40;
  54143. }
  54144. public function isCandidate(Tokens $tokens): bool
  54145. {
  54146. return $tokens->isAllTokenKindsFound([T_IF, T_ELSE]);
  54147. }
  54148. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  54149. {
  54150. foreach ($tokens as $index => $token) {
  54151. if (!$token->isGivenKind(T_ELSE)) {
  54152. continue;
  54153. }
  54154. $ifTokenIndex = $tokens->getNextMeaningfulToken($index);
  54155. if (!$tokens[$ifTokenIndex]->isGivenKind(T_IF)) {
  54156. continue;
  54157. }
  54158. $conditionEndBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($ifTokenIndex));
  54159. $afterConditionIndex = $tokens->getNextMeaningfulToken($conditionEndBraceIndex);
  54160. if ($tokens[$afterConditionIndex]->equals(':')) {
  54161. continue;
  54162. }
  54163. $tokens->clearAt($index + 1);
  54164. $tokens[$index] = new Token([T_ELSEIF, 'elseif']);
  54165. $tokens->clearAt($ifTokenIndex);
  54166. $beforeIfTokenIndex = $tokens->getPrevNonWhitespace($ifTokenIndex);
  54167. if ($tokens[$beforeIfTokenIndex]->isComment() && $tokens[$ifTokenIndex + 1]->isWhitespace()) {
  54168. $tokens->clearAt($ifTokenIndex + 1);
  54169. }
  54170. }
  54171. }
  54172. }
  54173. <?php
  54174. declare(strict_types=1);
  54175. namespace PhpCsFixer\Fixer\ControlStructure;
  54176. use PhpCsFixer\AbstractFixer;
  54177. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  54178. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  54179. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  54180. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  54181. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  54182. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  54183. use PhpCsFixer\FixerDefinition\CodeSample;
  54184. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54185. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54186. use PhpCsFixer\FixerDefinition\VersionSpecification;
  54187. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  54188. use PhpCsFixer\Tokenizer\CT;
  54189. use PhpCsFixer\Tokenizer\Token;
  54190. use PhpCsFixer\Tokenizer\Tokens;
  54191. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  54192. /**
  54193. @phpstan-type
  54194. @phpstan-type
  54195. @implements
  54196. */
  54197. final class TrailingCommaInMultilineFixer extends AbstractFixer implements ConfigurableFixerInterface
  54198. {
  54199. /**
  54200. @use */
  54201. use ConfigurableFixerTrait;
  54202. public const ELEMENTS_ARRAYS = 'arrays';
  54203. public const ELEMENTS_ARGUMENTS = 'arguments';
  54204. public const ELEMENTS_PARAMETERS = 'parameters';
  54205. private const MATCH_EXPRESSIONS = 'match';
  54206. private const ARRAY_DESTRUCTURING = 'array_destructuring';
  54207. public function getDefinition(): FixerDefinitionInterface
  54208. {
  54209. return new FixerDefinition(
  54210. 'Arguments lists, array destructuring lists, arrays that are multi-line, `match`-lines and parameters lists must have a trailing comma.',
  54211. [
  54212. new CodeSample("<?php\narray(\n 1,\n 2\n);\n"),
  54213. new CodeSample(
  54214. <<<'SAMPLE'
  54215. <?php
  54216. $x = [
  54217. 'foo',
  54218. <<<EOD
  54219. bar
  54220. EOD
  54221. ];
  54222. SAMPLE
  54223. ,
  54224. ['after_heredoc' => true]
  54225. ),
  54226. new CodeSample("<?php\nfoo(\n 1,\n 2\n);\n", ['elements' => [self::ELEMENTS_ARGUMENTS]]),
  54227. new VersionSpecificCodeSample("<?php\nfunction foo(\n \$x,\n \$y\n)\n{\n}\n", new VersionSpecification(8_00_00), ['elements' => [self::ELEMENTS_PARAMETERS]]),
  54228. ]
  54229. );
  54230. }
  54231. public function getPriority(): int
  54232. {
  54233. return 0;
  54234. }
  54235. public function isCandidate(Tokens $tokens): bool
  54236. {
  54237. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, '(', CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN]);
  54238. }
  54239. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  54240. {
  54241. return new FixerConfigurationResolver([
  54242. (new FixerOptionBuilder('after_heredoc', 'Whether a trailing comma should also be placed after heredoc end.'))
  54243. ->setAllowedTypes(['bool'])
  54244. ->setDefault(false)
  54245. ->getOption(),
  54246. (new FixerOptionBuilder('elements', \sprintf('Where to fix multiline trailing comma (PHP >= 8.0 for `%s` and `%s`).', self::ELEMENTS_PARAMETERS, self::MATCH_EXPRESSIONS)))
  54247. ->setAllowedTypes(['string[]'])
  54248. ->setAllowedValues([
  54249. new AllowedValueSubset([
  54250. self::ARRAY_DESTRUCTURING,
  54251. self::ELEMENTS_ARGUMENTS,
  54252. self::ELEMENTS_ARRAYS,
  54253. self::ELEMENTS_PARAMETERS,
  54254. self::MATCH_EXPRESSIONS,
  54255. ]),
  54256. ])
  54257. ->setDefault([self::ELEMENTS_ARRAYS])
  54258. ->getOption(),
  54259. ]);
  54260. }
  54261. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  54262. {
  54263. $configuredElements = $this->configuration['elements'];
  54264. $fixArrays = \in_array(self::ELEMENTS_ARRAYS, $configuredElements, true);
  54265. $fixArguments = \in_array(self::ELEMENTS_ARGUMENTS, $configuredElements, true);
  54266. $fixParameters = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::ELEMENTS_PARAMETERS, $configuredElements, true);
  54267. $fixMatch = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::MATCH_EXPRESSIONS, $configuredElements, true);
  54268. $fixDestructuring = \in_array(self::ARRAY_DESTRUCTURING, $configuredElements, true);
  54269. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  54270. if ($tokens[$index]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
  54271. if ($fixDestructuring) {
  54272. $this->fixBlock($tokens, $index);
  54273. }
  54274. continue;
  54275. }
  54276. if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  54277. if ($fixArrays) {
  54278. $this->fixBlock($tokens, $index);
  54279. }
  54280. continue;
  54281. }
  54282. if (!$tokens[$index]->equals('(')) {
  54283. continue;
  54284. }
  54285. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  54286. if ($tokens[$prevIndex]->isGivenKind(T_ARRAY)) {
  54287. if ($fixArrays) {
  54288. $this->fixBlock($tokens, $index);
  54289. }
  54290. continue;
  54291. }
  54292. if ($tokens[$prevIndex]->isGivenKind(T_LIST)) {
  54293. if ($fixDestructuring || $fixArguments) {
  54294. $this->fixBlock($tokens, $index);
  54295. }
  54296. continue;
  54297. }
  54298. if ($fixMatch && $tokens[$prevIndex]->isGivenKind(T_MATCH)) {
  54299. $this->fixBlock($tokens, $tokens->getNextTokenOfKind($index, ['{']));
  54300. continue;
  54301. }
  54302. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  54303. if ($fixArguments
  54304. && $tokens[$prevIndex]->equalsAny([']', [T_CLASS], [T_STRING], [T_VARIABLE], [T_STATIC], [T_ISSET], [T_UNSET], [T_LIST]])
  54305. && !$tokens[$prevPrevIndex]->isGivenKind(T_FUNCTION)
  54306. ) {
  54307. $this->fixBlock($tokens, $index);
  54308. continue;
  54309. }
  54310. if (
  54311. $fixParameters
  54312. && (
  54313. $tokens[$prevIndex]->isGivenKind(T_STRING)
  54314. && $tokens[$prevPrevIndex]->isGivenKind(T_FUNCTION)
  54315. || $tokens[$prevIndex]->isGivenKind([T_FN, T_FUNCTION])
  54316. )
  54317. ) {
  54318. $this->fixBlock($tokens, $index);
  54319. }
  54320. }
  54321. }
  54322. private function fixBlock(Tokens $tokens, int $startIndex): void
  54323. {
  54324. $tokensAnalyzer = new TokensAnalyzer($tokens);
  54325. if (!$tokensAnalyzer->isBlockMultiline($tokens, $startIndex)) {
  54326. return;
  54327. }
  54328. $blockType = Tokens::detectBlockType($tokens[$startIndex]);
  54329. $endIndex = $tokens->findBlockEnd($blockType['type'], $startIndex);
  54330. $beforeEndIndex = $tokens->getPrevMeaningfulToken($endIndex);
  54331. if (!$tokens->isPartialCodeMultiline($beforeEndIndex, $endIndex)) {
  54332. return;
  54333. }
  54334. $beforeEndToken = $tokens[$beforeEndIndex];
  54335. if (
  54336. $startIndex !== $beforeEndIndex && !$beforeEndToken->equals(',')
  54337. && (true === $this->configuration['after_heredoc'] || !$beforeEndToken->isGivenKind(T_END_HEREDOC))
  54338. ) {
  54339. $tokens->insertAt($beforeEndIndex + 1, new Token(','));
  54340. $endToken = $tokens[$endIndex];
  54341. if (!$endToken->isComment() && !$endToken->isWhitespace()) {
  54342. $tokens->ensureWhitespaceAtIndex($endIndex, 1, ' ');
  54343. }
  54344. }
  54345. }
  54346. }
  54347. <?php
  54348. declare(strict_types=1);
  54349. namespace PhpCsFixer\Fixer\ControlStructure;
  54350. use PhpCsFixer\AbstractFixer;
  54351. use PhpCsFixer\FixerDefinition\CodeSample;
  54352. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54353. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54354. use PhpCsFixer\Tokenizer\Analyzer\BlocksAnalyzer;
  54355. use PhpCsFixer\Tokenizer\Token;
  54356. use PhpCsFixer\Tokenizer\Tokens;
  54357. final class IncludeFixer extends AbstractFixer
  54358. {
  54359. public function getDefinition(): FixerDefinitionInterface
  54360. {
  54361. return new FixerDefinition(
  54362. 'Include/Require and file path should be divided with a single space. File path should not be placed within parentheses.',
  54363. [
  54364. new CodeSample(
  54365. '<?php
  54366. require ("sample1.php");
  54367. require_once "sample2.php";
  54368. include "sample3.php";
  54369. include_once("sample4.php");
  54370. '
  54371. ),
  54372. ]
  54373. );
  54374. }
  54375. public function isCandidate(Tokens $tokens): bool
  54376. {
  54377. return $tokens->isAnyTokenKindsFound([T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE]);
  54378. }
  54379. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  54380. {
  54381. $this->clearIncludies($tokens, $this->findIncludies($tokens));
  54382. }
  54383. private function clearIncludies(Tokens $tokens, array $includies): void
  54384. {
  54385. $blocksAnalyzer = new BlocksAnalyzer();
  54386. foreach ($includies as $includy) {
  54387. if (!$tokens[$includy['end']]->isGivenKind(T_CLOSE_TAG)) {
  54388. $afterEndIndex = $tokens->getNextNonWhitespace($includy['end']);
  54389. if (null === $afterEndIndex || !$tokens[$afterEndIndex]->isComment()) {
  54390. $tokens->removeLeadingWhitespace($includy['end']);
  54391. }
  54392. }
  54393. $braces = $includy['braces'];
  54394. if (null !== $braces) {
  54395. $prevIndex = $tokens->getPrevMeaningfulToken($includy['begin']);
  54396. $nextIndex = $tokens->getNextMeaningfulToken($braces['close']);
  54397. if (!$tokens[$nextIndex]->equalsAny([';', [T_CLOSE_TAG]]) && !$blocksAnalyzer->isBlock($tokens, $prevIndex, $nextIndex)) {
  54398. continue;
  54399. }
  54400. $this->removeWhitespaceAroundIfPossible($tokens, $braces['open']);
  54401. $this->removeWhitespaceAroundIfPossible($tokens, $braces['close']);
  54402. $tokens->clearTokenAndMergeSurroundingWhitespace($braces['open']);
  54403. $tokens->clearTokenAndMergeSurroundingWhitespace($braces['close']);
  54404. }
  54405. $nextIndex = $tokens->getNonEmptySibling($includy['begin'], 1);
  54406. if ($tokens[$nextIndex]->isWhitespace()) {
  54407. $tokens[$nextIndex] = new Token([T_WHITESPACE, ' ']);
  54408. } elseif (null !== $braces || $tokens[$nextIndex]->isGivenKind([T_VARIABLE, T_CONSTANT_ENCAPSED_STRING, T_COMMENT])) {
  54409. $tokens->insertAt($includy['begin'] + 1, new Token([T_WHITESPACE, ' ']));
  54410. }
  54411. }
  54412. }
  54413. private function findIncludies(Tokens $tokens): array
  54414. {
  54415. static $includyTokenKinds = [T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE];
  54416. $includies = [];
  54417. foreach ($tokens->findGivenKind($includyTokenKinds) as $includyTokens) {
  54418. foreach ($includyTokens as $index => $token) {
  54419. $includy = [
  54420. 'begin' => $index,
  54421. 'braces' => null,
  54422. 'end' => $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]),
  54423. ];
  54424. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  54425. if ($tokens[$braceOpenIndex]->equals('(')) {
  54426. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceOpenIndex);
  54427. $includy['braces'] = [
  54428. 'open' => $braceOpenIndex,
  54429. 'close' => $braceCloseIndex,
  54430. ];
  54431. }
  54432. $includies[$index] = $includy;
  54433. }
  54434. }
  54435. krsort($includies);
  54436. return $includies;
  54437. }
  54438. private function removeWhitespaceAroundIfPossible(Tokens $tokens, int $index): void
  54439. {
  54440. $nextIndex = $tokens->getNextNonWhitespace($index);
  54441. if (null === $nextIndex || !$tokens[$nextIndex]->isComment()) {
  54442. $tokens->removeLeadingWhitespace($index);
  54443. }
  54444. $prevIndex = $tokens->getPrevNonWhitespace($index);
  54445. if (null === $prevIndex || !$tokens[$prevIndex]->isComment()) {
  54446. $tokens->removeTrailingWhitespace($index);
  54447. }
  54448. }
  54449. }
  54450. <?php
  54451. declare(strict_types=1);
  54452. namespace PhpCsFixer\Fixer\ControlStructure;
  54453. use PhpCsFixer\AbstractProxyFixer;
  54454. use PhpCsFixer\Fixer\Basic\NoTrailingCommaInSinglelineFixer;
  54455. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  54456. use PhpCsFixer\FixerDefinition\CodeSample;
  54457. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54458. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54459. final class NoTrailingCommaInListCallFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  54460. {
  54461. public function getDefinition(): FixerDefinitionInterface
  54462. {
  54463. return new FixerDefinition(
  54464. 'Remove trailing commas in list function calls.',
  54465. [new CodeSample("<?php\nlist(\$a, \$b,) = foo();\n")]
  54466. );
  54467. }
  54468. public function getSuccessorsNames(): array
  54469. {
  54470. return array_keys($this->proxyFixers);
  54471. }
  54472. protected function createProxyFixers(): array
  54473. {
  54474. $fixer = new NoTrailingCommaInSinglelineFixer();
  54475. $fixer->configure(['elements' => ['array_destructuring']]);
  54476. return [$fixer];
  54477. }
  54478. }
  54479. <?php
  54480. declare(strict_types=1);
  54481. namespace PhpCsFixer\Fixer\ControlStructure;
  54482. use PhpCsFixer\AbstractFixer;
  54483. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  54484. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  54485. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  54486. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  54487. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  54488. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  54489. use PhpCsFixer\FixerDefinition\CodeSample;
  54490. use PhpCsFixer\FixerDefinition\FixerDefinition;
  54491. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  54492. use PhpCsFixer\Tokenizer\CT;
  54493. use PhpCsFixer\Tokenizer\FCT;
  54494. use PhpCsFixer\Tokenizer\Token;
  54495. use PhpCsFixer\Tokenizer\Tokens;
  54496. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  54497. /**
  54498. @phpstan-type
  54499. @phpstan-type
  54500. @implements
  54501. */
  54502. final class NoUnneededControlParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
  54503. {
  54504. /**
  54505. @use */
  54506. use ConfigurableFixerTrait;
  54507. private const BLOCK_TYPES = [
  54508. Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE,
  54509. Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE,
  54510. Tokens::BLOCK_TYPE_CURLY_BRACE,
  54511. Tokens::BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE,
  54512. Tokens::BLOCK_TYPE_DYNAMIC_PROP_BRACE,
  54513. Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE,
  54514. Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE,
  54515. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  54516. ];
  54517. private const BEFORE_TYPES = [
  54518. ';',
  54519. '{',
  54520. [T_OPEN_TAG],
  54521. [T_OPEN_TAG_WITH_ECHO],
  54522. [T_ECHO],
  54523. [T_PRINT],
  54524. [T_RETURN],
  54525. [T_THROW],
  54526. [T_YIELD],
  54527. [T_YIELD_FROM],
  54528. [T_BREAK],
  54529. [T_CONTINUE],
  54530. [T_REQUIRE],
  54531. [T_REQUIRE_ONCE],
  54532. [T_INCLUDE],
  54533. [T_INCLUDE_ONCE],
  54534. ];
  54535. private const CONFIG_OPTIONS = [
  54536. 'break',
  54537. 'clone',
  54538. 'continue',
  54539. 'echo_print',
  54540. 'negative_instanceof',
  54541. 'others',
  54542. 'return',
  54543. 'switch_case',
  54544. 'yield',
  54545. 'yield_from',
  54546. ];
  54547. private const TOKEN_TYPE_CONFIG_MAP = [
  54548. T_BREAK => 'break',
  54549. T_CASE => 'switch_case',
  54550. T_CONTINUE => 'continue',
  54551. T_ECHO => 'echo_print',
  54552. T_PRINT => 'echo_print',
  54553. T_RETURN => 'return',
  54554. T_YIELD => 'yield',
  54555. T_YIELD_FROM => 'yield_from',
  54556. ];
  54557. private const TOKEN_TYPE_NO_CONFIG = [
  54558. T_REQUIRE,
  54559. T_REQUIRE_ONCE,
  54560. T_INCLUDE,
  54561. T_INCLUDE_ONCE,
  54562. ];
  54563. private const KNOWN_NEGATIVE_PRE_TYPES = [
  54564. [CT::T_CLASS_CONSTANT],
  54565. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  54566. [CT::T_RETURN_REF],
  54567. [CT::T_USE_LAMBDA],
  54568. [T_ARRAY],
  54569. [T_CATCH],
  54570. [T_CLASS],
  54571. [T_DECLARE],
  54572. [T_ELSEIF],
  54573. [T_EMPTY],
  54574. [T_EXIT],
  54575. [T_EVAL],
  54576. [T_FN],
  54577. [T_FOREACH],
  54578. [T_FOR],
  54579. [T_FUNCTION],
  54580. [T_HALT_COMPILER],
  54581. [T_IF],
  54582. [T_ISSET],
  54583. [T_LIST],
  54584. [T_STRING],
  54585. [T_SWITCH],
  54586. [T_STATIC],
  54587. [T_UNSET],
  54588. [T_VARIABLE],
  54589. [T_WHILE],
  54590. [T_REQUIRE],
  54591. [T_REQUIRE_ONCE],
  54592. [T_INCLUDE],
  54593. [T_INCLUDE_ONCE],
  54594. [FCT::T_MATCH],
  54595. ];
  54596. private array $noopTypes;
  54597. private TokensAnalyzer $tokensAnalyzer;
  54598. public function __construct()
  54599. {
  54600. parent::__construct();
  54601. $this->noopTypes = [
  54602. '$',
  54603. [T_CONSTANT_ENCAPSED_STRING],
  54604. [T_DNUMBER],
  54605. [T_DOUBLE_COLON],
  54606. [T_LNUMBER],
  54607. [T_NS_SEPARATOR],
  54608. [T_STRING],
  54609. [T_VARIABLE],
  54610. [T_STATIC],
  54611. [T_CLASS_C],
  54612. [T_DIR],
  54613. [T_FILE],
  54614. [T_FUNC_C],
  54615. [T_LINE],
  54616. [T_METHOD_C],
  54617. [T_NS_C],
  54618. [T_TRAIT_C],
  54619. ];
  54620. foreach (Token::getObjectOperatorKinds() as $kind) {
  54621. $this->noopTypes[] = [$kind];
  54622. }
  54623. }
  54624. public function getDefinition(): FixerDefinitionInterface
  54625. {
  54626. return new FixerDefinition(
  54627. 'Removes unneeded parentheses around control statements.',
  54628. [
  54629. new CodeSample(
  54630. '<?php
  54631. while ($x) { while ($y) { break (2); } }
  54632. clone($a);
  54633. while ($y) { continue (2); }
  54634. echo("foo");
  54635. print("foo");
  54636. return (1 + 2);
  54637. switch ($a) { case($x); }
  54638. yield(2);
  54639. '
  54640. ),
  54641. new CodeSample(
  54642. '<?php
  54643. while ($x) { while ($y) { break (2); } }
  54644. clone($a);
  54645. while ($y) { continue (2); }
  54646. ',
  54647. ['statements' => ['break', 'continue']]
  54648. ),
  54649. ]
  54650. );
  54651. }
  54652. public function getPriority(): int
  54653. {
  54654. return 30;
  54655. }
  54656. public function isCandidate(Tokens $tokens): bool
  54657. {
  54658. return $tokens->isAnyTokenKindsFound(['(', CT::T_BRACE_CLASS_INSTANTIATION_OPEN]);
  54659. }
  54660. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  54661. {
  54662. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  54663. foreach ($tokens as $openIndex => $token) {
  54664. if ($token->equals('(')) {
  54665. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  54666. } elseif ($token->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_OPEN)) {
  54667. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_BRACE_CLASS_INSTANTIATION, $openIndex);
  54668. } else {
  54669. continue;
  54670. }
  54671. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($openIndex);
  54672. $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
  54673. if ($tokens->getNextMeaningfulToken($openIndex) === $closeIndex) {
  54674. if ($this->isExitStatement($tokens, $beforeOpenIndex)) {
  54675. $this->removeUselessParenthesisPair($tokens, $beforeOpenIndex, $afterCloseIndex, $openIndex, $closeIndex, 'others');
  54676. }
  54677. continue;
  54678. }
  54679. if ($tokens[$beforeOpenIndex]->equalsAny(self::KNOWN_NEGATIVE_PRE_TYPES)) {
  54680. continue;
  54681. }
  54682. if ($this->isUselessWrapped($tokens, $beforeOpenIndex, $afterCloseIndex)) {
  54683. $this->removeUselessParenthesisPair($tokens, $beforeOpenIndex, $afterCloseIndex, $openIndex, $closeIndex, $this->getConfigType($tokens, $beforeOpenIndex));
  54684. continue;
  54685. }
  54686. if ($this->isCloneStatement($tokens, $beforeOpenIndex)) {
  54687. if ($this->isWrappedCloneArgument($tokens, $beforeOpenIndex, $openIndex, $closeIndex, $afterCloseIndex)) {
  54688. $this->removeUselessParenthesisPair($tokens, $beforeOpenIndex, $afterCloseIndex, $openIndex, $closeIndex, 'clone');
  54689. }
  54690. continue;
  54691. }
  54692. $instanceOfIndex = $this->getIndexOfInstanceOfStatement($tokens, $openIndex, $closeIndex);
  54693. if (null !== $instanceOfIndex) {
  54694. if ($this->isWrappedInstanceOf($tokens, $instanceOfIndex, $beforeOpenIndex, $openIndex, $closeIndex, $afterCloseIndex)) {
  54695. $this->removeUselessParenthesisPair(
  54696. $tokens,
  54697. $beforeOpenIndex,
  54698. $afterCloseIndex,
  54699. $openIndex,
  54700. $closeIndex,
  54701. $tokens[$beforeOpenIndex]->equals('!') ? 'negative_instanceof' : 'others'
  54702. );
  54703. }
  54704. continue;
  54705. }
  54706. if ($this->isWrappedPartOfOperation($tokens, $beforeOpenIndex, $openIndex, $closeIndex, $afterCloseIndex)) {
  54707. $this->removeUselessParenthesisPair($tokens, $beforeOpenIndex, $afterCloseIndex, $openIndex, $closeIndex, $this->getConfigType($tokens, $beforeOpenIndex));
  54708. }
  54709. }
  54710. }
  54711. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  54712. {
  54713. $defaults = array_filter(
  54714. self::CONFIG_OPTIONS,
  54715. static fn (string $option): bool => 'negative_instanceof' !== $option && 'others' !== $option && 'yield_from' !== $option
  54716. );
  54717. return new FixerConfigurationResolver([
  54718. (new FixerOptionBuilder('statements', 'List of control statements to fix.'))
  54719. ->setAllowedTypes(['string[]'])
  54720. ->setAllowedValues([new AllowedValueSubset(self::CONFIG_OPTIONS)])
  54721. ->setDefault(array_values($defaults))
  54722. ->getOption(),
  54723. ]);
  54724. }
  54725. private function isUselessWrapped(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54726. {
  54727. return
  54728. $this->isSingleStatement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54729. || $this->isWrappedFnBody($tokens, $beforeOpenIndex, $afterCloseIndex)
  54730. || $this->isWrappedForElement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54731. || $this->isWrappedLanguageConstructArgument($tokens, $beforeOpenIndex, $afterCloseIndex)
  54732. || $this->isWrappedSequenceElement($tokens, $beforeOpenIndex, $afterCloseIndex);
  54733. }
  54734. private function isExitStatement(Tokens $tokens, int $beforeOpenIndex): bool
  54735. {
  54736. return $tokens[$beforeOpenIndex]->isGivenKind(T_EXIT);
  54737. }
  54738. private function isCloneStatement(Tokens $tokens, int $beforeOpenIndex): bool
  54739. {
  54740. return $tokens[$beforeOpenIndex]->isGivenKind(T_CLONE);
  54741. }
  54742. private function isWrappedCloneArgument(Tokens $tokens, int $beforeOpenIndex, int $openIndex, int $closeIndex, int $afterCloseIndex): bool
  54743. {
  54744. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54745. if (
  54746. !(
  54747. $tokens[$beforeOpenIndex]->equals('?')
  54748. || $this->isSimpleAssignment($tokens, $beforeOpenIndex, $afterCloseIndex)
  54749. || $this->isSingleStatement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54750. || $this->isWrappedFnBody($tokens, $beforeOpenIndex, $afterCloseIndex)
  54751. || $this->isWrappedForElement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54752. || $this->isWrappedSequenceElement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54753. )
  54754. ) {
  54755. return false;
  54756. }
  54757. $newCandidateIndex = $tokens->getNextMeaningfulToken($openIndex);
  54758. if ($tokens[$newCandidateIndex]->isGivenKind(T_NEW)) {
  54759. $openIndex = $newCandidateIndex;
  54760. }
  54761. return !$this->containsOperation($tokens, $openIndex, $closeIndex);
  54762. }
  54763. private function getIndexOfInstanceOfStatement(Tokens $tokens, int $openIndex, int $closeIndex): ?int
  54764. {
  54765. $instanceOfIndex = $tokens->findGivenKind(T_INSTANCEOF, $openIndex, $closeIndex);
  54766. return 1 === \count($instanceOfIndex) ? array_key_first($instanceOfIndex) : null;
  54767. }
  54768. private function isWrappedInstanceOf(Tokens $tokens, int $instanceOfIndex, int $beforeOpenIndex, int $openIndex, int $closeIndex, int $afterCloseIndex): bool
  54769. {
  54770. if (
  54771. $this->containsOperation($tokens, $openIndex, $instanceOfIndex)
  54772. || $this->containsOperation($tokens, $instanceOfIndex, $closeIndex)
  54773. ) {
  54774. return false;
  54775. }
  54776. if ($tokens[$beforeOpenIndex]->equals('!')) {
  54777. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54778. }
  54779. return
  54780. $this->isSimpleAssignment($tokens, $beforeOpenIndex, $afterCloseIndex)
  54781. || $this->isSingleStatement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54782. || $this->isWrappedFnBody($tokens, $beforeOpenIndex, $afterCloseIndex)
  54783. || $this->isWrappedForElement($tokens, $beforeOpenIndex, $afterCloseIndex)
  54784. || $this->isWrappedSequenceElement($tokens, $beforeOpenIndex, $afterCloseIndex);
  54785. }
  54786. private function isWrappedPartOfOperation(Tokens $tokens, int $beforeOpenIndex, int $openIndex, int $closeIndex, int $afterCloseIndex): bool
  54787. {
  54788. if ($this->containsOperation($tokens, $openIndex, $closeIndex)) {
  54789. return false;
  54790. }
  54791. $boundariesMoved = false;
  54792. if ($this->isPreUnaryOperation($tokens, $beforeOpenIndex)) {
  54793. $beforeOpenIndex = $this->getBeforePreUnaryOperation($tokens, $beforeOpenIndex);
  54794. $boundariesMoved = true;
  54795. }
  54796. if ($this->isAccess($tokens, $afterCloseIndex)) {
  54797. $afterCloseIndex = $this->getAfterAccess($tokens, $afterCloseIndex);
  54798. $boundariesMoved = true;
  54799. if ($this->tokensAnalyzer->isUnarySuccessorOperator($afterCloseIndex)) {
  54800. $afterCloseIndex = $tokens->getNextMeaningfulToken($afterCloseIndex);
  54801. }
  54802. }
  54803. if ($boundariesMoved) {
  54804. if ($tokens[$beforeOpenIndex]->equalsAny(self::KNOWN_NEGATIVE_PRE_TYPES)) {
  54805. return false;
  54806. }
  54807. if ($this->isUselessWrapped($tokens, $beforeOpenIndex, $afterCloseIndex)) {
  54808. return true;
  54809. }
  54810. }
  54811. $beforeIsBinaryOperation = $this->tokensAnalyzer->isBinaryOperator($beforeOpenIndex);
  54812. $afterIsBinaryOperation = $this->tokensAnalyzer->isBinaryOperator($afterCloseIndex);
  54813. if ($beforeIsBinaryOperation && $afterIsBinaryOperation) {
  54814. return true;
  54815. }
  54816. $beforeToken = $tokens[$beforeOpenIndex];
  54817. $afterToken = $tokens[$afterCloseIndex];
  54818. $beforeIsBlockOpenOrComma = $beforeToken->equals(',') || null !== $this->getBlock($tokens, $beforeOpenIndex, true);
  54819. $afterIsBlockEndOrComma = $afterToken->equals(',') || null !== $this->getBlock($tokens, $afterCloseIndex, false);
  54820. if (($beforeIsBlockOpenOrComma && $afterIsBinaryOperation) || ($beforeIsBinaryOperation && $afterIsBlockEndOrComma)) {
  54821. return true;
  54822. }
  54823. if ($tokens[$beforeOpenIndex]->equals('}')) {
  54824. $beforeIsStatementOpen = !$this->closeCurlyBelongsToDynamicElement($tokens, $beforeOpenIndex);
  54825. } else {
  54826. $beforeIsStatementOpen = $beforeToken->equalsAny(self::BEFORE_TYPES) || $beforeToken->isGivenKind(T_CASE);
  54827. }
  54828. $afterIsStatementEnd = $afterToken->equalsAny([';', [T_CLOSE_TAG]]);
  54829. return
  54830. ($beforeIsStatementOpen && $afterIsBinaryOperation)
  54831. || ($beforeIsBinaryOperation && $afterIsStatementEnd);
  54832. }
  54833. private function isWrappedLanguageConstructArgument(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54834. {
  54835. if (!$tokens[$beforeOpenIndex]->isGivenKind([T_PRINT, T_YIELD, T_YIELD_FROM, T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE])) {
  54836. return false;
  54837. }
  54838. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54839. return $this->isWrappedSequenceElement($tokens, $beforeOpenIndex, $afterCloseIndex);
  54840. }
  54841. private function isSingleStatement(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54842. {
  54843. if ($tokens[$beforeOpenIndex]->isGivenKind(T_CASE)) {
  54844. return $tokens[$afterCloseIndex]->equalsAny([':', ';']);
  54845. }
  54846. if (!$tokens[$afterCloseIndex]->equalsAny([';', [T_CLOSE_TAG]])) {
  54847. return false;
  54848. }
  54849. if ($tokens[$beforeOpenIndex]->equals('}')) {
  54850. return !$this->closeCurlyBelongsToDynamicElement($tokens, $beforeOpenIndex);
  54851. }
  54852. return $tokens[$beforeOpenIndex]->equalsAny(self::BEFORE_TYPES);
  54853. }
  54854. private function isSimpleAssignment(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54855. {
  54856. return $tokens[$beforeOpenIndex]->equals('=') && $tokens[$afterCloseIndex]->equalsAny([';', [T_CLOSE_TAG]]);
  54857. }
  54858. private function isWrappedSequenceElement(Tokens $tokens, int $startIndex, int $endIndex): bool
  54859. {
  54860. $startIsComma = $tokens[$startIndex]->equals(',');
  54861. $endIsComma = $tokens[$endIndex]->equals(',');
  54862. if ($startIsComma && $endIsComma) {
  54863. return true;
  54864. }
  54865. $blockTypeStart = $this->getBlock($tokens, $startIndex, true);
  54866. $blockTypeEnd = $this->getBlock($tokens, $endIndex, false);
  54867. return
  54868. ($startIsComma && null !== $blockTypeEnd)
  54869. || ($endIsComma && null !== $blockTypeStart)
  54870. || (null !== $blockTypeEnd && null !== $blockTypeStart);
  54871. }
  54872. private function isWrappedForElement(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54873. {
  54874. $forCandidateIndex = null;
  54875. if ($tokens[$beforeOpenIndex]->equals('(') && $tokens[$afterCloseIndex]->equals(';')) {
  54876. $forCandidateIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54877. } elseif ($tokens[$afterCloseIndex]->equals(')') && $tokens[$beforeOpenIndex]->equals(';')) {
  54878. $forCandidateIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $afterCloseIndex);
  54879. $forCandidateIndex = $tokens->getPrevMeaningfulToken($forCandidateIndex);
  54880. }
  54881. return null !== $forCandidateIndex && $tokens[$forCandidateIndex]->isGivenKind(T_FOR);
  54882. }
  54883. private function isWrappedFnBody(Tokens $tokens, int $beforeOpenIndex, int $afterCloseIndex): bool
  54884. {
  54885. if (!$tokens[$beforeOpenIndex]->isGivenKind(T_DOUBLE_ARROW)) {
  54886. return false;
  54887. }
  54888. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54889. if ($tokens[$beforeOpenIndex]->isGivenKind(T_STRING)) {
  54890. while (true) {
  54891. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54892. if (!$tokens[$beforeOpenIndex]->isGivenKind([T_STRING, CT::T_TYPE_INTERSECTION, CT::T_TYPE_ALTERNATION])) {
  54893. break;
  54894. }
  54895. }
  54896. if (!$tokens[$beforeOpenIndex]->isGivenKind(CT::T_TYPE_COLON)) {
  54897. return false;
  54898. }
  54899. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54900. }
  54901. if (!$tokens[$beforeOpenIndex]->equals(')')) {
  54902. return false;
  54903. }
  54904. $beforeOpenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeOpenIndex);
  54905. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54906. if ($tokens[$beforeOpenIndex]->isGivenKind(CT::T_RETURN_REF)) {
  54907. $beforeOpenIndex = $tokens->getPrevMeaningfulToken($beforeOpenIndex);
  54908. }
  54909. if (!$tokens[$beforeOpenIndex]->isGivenKind(T_FN)) {
  54910. return false;
  54911. }
  54912. return $tokens[$afterCloseIndex]->equalsAny([';', ',', [T_CLOSE_TAG]]);
  54913. }
  54914. private function isPreUnaryOperation(Tokens $tokens, int $index): bool
  54915. {
  54916. return $this->tokensAnalyzer->isUnaryPredecessorOperator($index) || $tokens[$index]->isCast();
  54917. }
  54918. private function getBeforePreUnaryOperation(Tokens $tokens, int $index): int
  54919. {
  54920. do {
  54921. $index = $tokens->getPrevMeaningfulToken($index);
  54922. } while ($this->isPreUnaryOperation($tokens, $index));
  54923. return $index;
  54924. }
  54925. private function isAccess(Tokens $tokens, int $index): bool
  54926. {
  54927. $token = $tokens[$index];
  54928. return $token->isObjectOperator() || $token->equals('[') || $token->isGivenKind([CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]);
  54929. }
  54930. private function getAfterAccess(Tokens $tokens, int $index): int
  54931. {
  54932. while (true) {
  54933. $block = $this->getBlock($tokens, $index, true);
  54934. if (null !== $block) {
  54935. $index = $tokens->findBlockEnd($block['type'], $index);
  54936. $index = $tokens->getNextMeaningfulToken($index);
  54937. continue;
  54938. }
  54939. if (
  54940. $tokens[$index]->isObjectOperator()
  54941. || $tokens[$index]->equalsAny(['$', [T_PAAMAYIM_NEKUDOTAYIM], [T_STRING], [T_VARIABLE]])
  54942. ) {
  54943. $index = $tokens->getNextMeaningfulToken($index);
  54944. continue;
  54945. }
  54946. break;
  54947. }
  54948. return $index;
  54949. }
  54950. private function getBlock(Tokens $tokens, int $index, bool $isStart): ?array
  54951. {
  54952. $block = Tokens::detectBlockType($tokens[$index]);
  54953. return null !== $block && $isStart === $block['isStart'] && \in_array($block['type'], self::BLOCK_TYPES, true) ? $block : null;
  54954. }
  54955. private function containsOperation(Tokens $tokens, int $startIndex, int $endIndex): bool
  54956. {
  54957. while (true) {
  54958. $startIndex = $tokens->getNextMeaningfulToken($startIndex);
  54959. if ($startIndex === $endIndex) {
  54960. break;
  54961. }
  54962. $block = Tokens::detectBlockType($tokens[$startIndex]);
  54963. if (null !== $block && $block['isStart']) {
  54964. $startIndex = $tokens->findBlockEnd($block['type'], $startIndex);
  54965. continue;
  54966. }
  54967. if (!$tokens[$startIndex]->equalsAny($this->noopTypes)) {
  54968. return true;
  54969. }
  54970. }
  54971. return false;
  54972. }
  54973. private function getConfigType(Tokens $tokens, int $beforeOpenIndex): ?string
  54974. {
  54975. if ($tokens[$beforeOpenIndex]->isGivenKind(self::TOKEN_TYPE_NO_CONFIG)) {
  54976. return null;
  54977. }
  54978. foreach (self::TOKEN_TYPE_CONFIG_MAP as $type => $configItem) {
  54979. if ($tokens[$beforeOpenIndex]->isGivenKind($type)) {
  54980. return $configItem;
  54981. }
  54982. }
  54983. return 'others';
  54984. }
  54985. private function removeUselessParenthesisPair(
  54986. Tokens $tokens,
  54987. int $beforeOpenIndex,
  54988. int $afterCloseIndex,
  54989. int $openIndex,
  54990. int $closeIndex,
  54991. ?string $configType
  54992. ): void {
  54993. $statements = $this->configuration['statements'];
  54994. if (null === $configType || !\in_array($configType, $statements, true)) {
  54995. return;
  54996. }
  54997. $needsSpaceAfter = !$this->isAccess($tokens, $afterCloseIndex)
  54998. && !$tokens[$afterCloseIndex]->equalsAny([';', ',', [T_CLOSE_TAG]])
  54999. && null === $this->getBlock($tokens, $afterCloseIndex, false)
  55000. && !($tokens[$afterCloseIndex]->equalsAny([':', ';']) && $tokens[$beforeOpenIndex]->isGivenKind(T_CASE));
  55001. $needsSpaceBefore = !$this->isPreUnaryOperation($tokens, $beforeOpenIndex)
  55002. && !$tokens[$beforeOpenIndex]->equalsAny(['}', [T_EXIT], [T_OPEN_TAG]])
  55003. && null === $this->getBlock($tokens, $beforeOpenIndex, true);
  55004. $this->removeBrace($tokens, $closeIndex, $needsSpaceAfter);
  55005. $this->removeBrace($tokens, $openIndex, $needsSpaceBefore);
  55006. }
  55007. private function removeBrace(Tokens $tokens, int $index, bool $needsSpace): void
  55008. {
  55009. if ($needsSpace) {
  55010. foreach ([-1, 1] as $direction) {
  55011. $siblingIndex = $tokens->getNonEmptySibling($index, $direction);
  55012. if ($tokens[$siblingIndex]->isWhitespace() || $tokens[$siblingIndex]->isComment()) {
  55013. $needsSpace = false;
  55014. break;
  55015. }
  55016. }
  55017. }
  55018. if ($needsSpace) {
  55019. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  55020. } else {
  55021. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  55022. }
  55023. }
  55024. private function closeCurlyBelongsToDynamicElement(Tokens $tokens, int $beforeOpenIndex): bool
  55025. {
  55026. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $beforeOpenIndex);
  55027. $index = $tokens->getPrevMeaningfulToken($index);
  55028. if ($tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  55029. return true;
  55030. }
  55031. if ($tokens[$index]->equals(':')) {
  55032. $index = $tokens->getPrevTokenOfKind($index, [[T_CASE], '?']);
  55033. return !$tokens[$index]->isGivenKind(T_CASE);
  55034. }
  55035. return false;
  55036. }
  55037. }
  55038. <?php
  55039. declare(strict_types=1);
  55040. namespace PhpCsFixer\Fixer\ControlStructure;
  55041. use PhpCsFixer\AbstractFixer;
  55042. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  55043. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  55044. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  55045. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  55046. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  55047. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  55048. use PhpCsFixer\FixerDefinition\CodeSample;
  55049. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55050. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55051. use PhpCsFixer\Preg;
  55052. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  55053. use PhpCsFixer\Tokenizer\FCT;
  55054. use PhpCsFixer\Tokenizer\Token;
  55055. use PhpCsFixer\Tokenizer\Tokens;
  55056. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  55057. use Symfony\Component\OptionsResolver\Options;
  55058. /**
  55059. @phpstan-type
  55060. @phpstan-type
  55061. @implements
  55062. */
  55063. final class NoBreakCommentFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  55064. {
  55065. /**
  55066. @use */
  55067. use ConfigurableFixerTrait;
  55068. private const STRUCTURE_KINDS = [T_FOR, T_FOREACH, T_WHILE, T_IF, T_ELSEIF, T_SWITCH, T_FUNCTION, FCT::T_MATCH];
  55069. public function getDefinition(): FixerDefinitionInterface
  55070. {
  55071. return new FixerDefinition(
  55072. 'There must be a comment when fall-through is intentional in a non-empty case body.',
  55073. [
  55074. new CodeSample(
  55075. '<?php
  55076. switch ($foo) {
  55077. case 1:
  55078. foo();
  55079. case 2:
  55080. bar();
  55081. // no break
  55082. break;
  55083. case 3:
  55084. baz();
  55085. }
  55086. '
  55087. ),
  55088. new CodeSample(
  55089. '<?php
  55090. switch ($foo) {
  55091. case 1:
  55092. foo();
  55093. case 2:
  55094. foo();
  55095. }
  55096. ',
  55097. ['comment_text' => 'some comment']
  55098. ),
  55099. ],
  55100. 'Adds a "no break" comment before fall-through cases, and removes it if there is no fall-through.'
  55101. );
  55102. }
  55103. public function isCandidate(Tokens $tokens): bool
  55104. {
  55105. return $tokens->isTokenKindFound(T_SWITCH);
  55106. }
  55107. public function getPriority(): int
  55108. {
  55109. return 0;
  55110. }
  55111. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  55112. {
  55113. return new FixerConfigurationResolver([
  55114. (new FixerOptionBuilder('comment_text', 'The text to use in the added comment and to detect it.'))
  55115. ->setAllowedTypes(['string'])
  55116. ->setAllowedValues([
  55117. static function (string $value): bool {
  55118. if (Preg::match('/\R/', $value)) {
  55119. throw new InvalidOptionsException('The comment text must not contain new lines.');
  55120. }
  55121. return true;
  55122. },
  55123. ])
  55124. ->setNormalizer(static fn (Options $options, string $value): string => rtrim($value))
  55125. ->setDefault('no break')
  55126. ->getOption(),
  55127. ]);
  55128. }
  55129. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  55130. {
  55131. for ($index = \count($tokens) - 1; $index >= 0; --$index) {
  55132. if ($tokens[$index]->isGivenKind(T_DEFAULT)) {
  55133. if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_DOUBLE_ARROW)) {
  55134. continue;
  55135. }
  55136. } elseif (!$tokens[$index]->isGivenKind(T_CASE)) {
  55137. continue;
  55138. }
  55139. $this->fixCase($tokens, $tokens->getNextTokenOfKind($index, [':', ';']));
  55140. }
  55141. }
  55142. private function fixCase(Tokens $tokens, int $casePosition): void
  55143. {
  55144. $empty = true;
  55145. $fallThrough = true;
  55146. $commentPosition = null;
  55147. for ($i = $casePosition + 1, $max = \count($tokens); $i < $max; ++$i) {
  55148. if ($tokens[$i]->isGivenKind([...self::STRUCTURE_KINDS, T_ELSE, T_DO, T_CLASS])) {
  55149. $empty = false;
  55150. $i = $this->getStructureEnd($tokens, $i);
  55151. continue;
  55152. }
  55153. if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_GOTO])) {
  55154. $fallThrough = false;
  55155. continue;
  55156. }
  55157. if ($tokens[$i]->isGivenKind(T_THROW)) {
  55158. $previousIndex = $tokens->getPrevMeaningfulToken($i);
  55159. if ($previousIndex === $casePosition || $tokens[$previousIndex]->equalsAny(['{', ';', '}', [T_OPEN_TAG]])) {
  55160. $fallThrough = false;
  55161. }
  55162. continue;
  55163. }
  55164. if ($tokens[$i]->equals('}') || $tokens[$i]->isGivenKind(T_ENDSWITCH)) {
  55165. if (null !== $commentPosition) {
  55166. $this->removeComment($tokens, $commentPosition);
  55167. }
  55168. break;
  55169. }
  55170. if ($this->isNoBreakComment($tokens[$i])) {
  55171. $commentPosition = $i;
  55172. continue;
  55173. }
  55174. if ($tokens[$i]->isGivenKind([T_CASE, T_DEFAULT])) {
  55175. if (!$empty && $fallThrough) {
  55176. if (null !== $commentPosition && $tokens->getPrevNonWhitespace($i) !== $commentPosition) {
  55177. $this->removeComment($tokens, $commentPosition);
  55178. $commentPosition = null;
  55179. }
  55180. if (null === $commentPosition) {
  55181. $this->insertCommentAt($tokens, $i);
  55182. } else {
  55183. $text = $this->configuration['comment_text'];
  55184. $tokens[$commentPosition] = new Token([
  55185. $tokens[$commentPosition]->getId(),
  55186. str_ireplace($text, $text, $tokens[$commentPosition]->getContent()),
  55187. ]);
  55188. $this->ensureNewLineAt($tokens, $commentPosition);
  55189. }
  55190. } elseif (null !== $commentPosition) {
  55191. $this->removeComment($tokens, $commentPosition);
  55192. }
  55193. break;
  55194. }
  55195. if (!$tokens[$i]->isGivenKind([T_COMMENT, T_WHITESPACE])) {
  55196. $empty = false;
  55197. }
  55198. }
  55199. }
  55200. private function isNoBreakComment(Token $token): bool
  55201. {
  55202. if (!$token->isComment()) {
  55203. return false;
  55204. }
  55205. $text = preg_quote($this->configuration['comment_text'], '~');
  55206. return Preg::match("~^((//|#)\\s*{$text}\\s*)|(/\\*\\*?\\s*{$text}(\\s+.*)*\\*/)$~i", $token->getContent());
  55207. }
  55208. private function insertCommentAt(Tokens $tokens, int $casePosition): void
  55209. {
  55210. $lineEnding = $this->whitespacesConfig->getLineEnding();
  55211. $newlinePosition = $this->ensureNewLineAt($tokens, $casePosition);
  55212. $newlineToken = $tokens[$newlinePosition];
  55213. $nbNewlines = substr_count($newlineToken->getContent(), $lineEnding);
  55214. if ($newlineToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $newlineToken->getContent())) {
  55215. ++$nbNewlines;
  55216. } elseif ($tokens[$newlinePosition - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$newlinePosition - 1]->getContent())) {
  55217. ++$nbNewlines;
  55218. if (!Preg::match('/\R/', $newlineToken->getContent())) {
  55219. $tokens[$newlinePosition] = new Token([$newlineToken->getId(), $lineEnding.$newlineToken->getContent()]);
  55220. }
  55221. }
  55222. if ($nbNewlines > 1) {
  55223. Preg::match('/^(.*?)(\R\h*)$/s', $newlineToken->getContent(), $matches);
  55224. $indent = WhitespacesAnalyzer::detectIndent($tokens, $newlinePosition - 1);
  55225. $tokens[$newlinePosition] = new Token([$newlineToken->getId(), $matches[1].$lineEnding.$indent]);
  55226. $tokens->insertAt(++$newlinePosition, new Token([T_WHITESPACE, $matches[2]]));
  55227. }
  55228. $tokens->insertAt($newlinePosition, new Token([T_COMMENT, '// '.$this->configuration['comment_text']]));
  55229. $this->ensureNewLineAt($tokens, $newlinePosition);
  55230. }
  55231. private function ensureNewLineAt(Tokens $tokens, int $position): int
  55232. {
  55233. $lineEnding = $this->whitespacesConfig->getLineEnding();
  55234. $content = $lineEnding.WhitespacesAnalyzer::detectIndent($tokens, $position);
  55235. $whitespaceToken = $tokens[$position - 1];
  55236. if (!$whitespaceToken->isGivenKind(T_WHITESPACE)) {
  55237. if ($whitespaceToken->isGivenKind(T_OPEN_TAG)) {
  55238. $content = Preg::replace('/\R/', '', $content);
  55239. if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
  55240. $tokens[$position - 1] = new Token([T_OPEN_TAG, Preg::replace('/\s+$/', $lineEnding, $whitespaceToken->getContent())]);
  55241. }
  55242. }
  55243. if ('' !== $content) {
  55244. $tokens->insertAt($position, new Token([T_WHITESPACE, $content]));
  55245. return $position;
  55246. }
  55247. return $position - 1;
  55248. }
  55249. if ($tokens[$position - 2]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$position - 2]->getContent())) {
  55250. $content = Preg::replace('/^\R/', '', $content);
  55251. }
  55252. if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
  55253. $tokens[$position - 1] = new Token([T_WHITESPACE, $content]);
  55254. }
  55255. return $position - 1;
  55256. }
  55257. private function removeComment(Tokens $tokens, int $commentPosition): void
  55258. {
  55259. if ($tokens[$tokens->getPrevNonWhitespace($commentPosition)]->isGivenKind(T_OPEN_TAG)) {
  55260. $whitespacePosition = $commentPosition + 1;
  55261. $regex = '/^\R\h*/';
  55262. } else {
  55263. $whitespacePosition = $commentPosition - 1;
  55264. $regex = '/\R\h*$/';
  55265. }
  55266. $whitespaceToken = $tokens[$whitespacePosition];
  55267. if ($whitespaceToken->isGivenKind(T_WHITESPACE)) {
  55268. $content = Preg::replace($regex, '', $whitespaceToken->getContent());
  55269. $tokens->ensureWhitespaceAtIndex($whitespacePosition, 0, $content);
  55270. }
  55271. $tokens->clearTokenAndMergeSurroundingWhitespace($commentPosition);
  55272. }
  55273. private function getStructureEnd(Tokens $tokens, int $position): int
  55274. {
  55275. $initialToken = $tokens[$position];
  55276. if ($initialToken->isGivenKind(self::STRUCTURE_KINDS)) {
  55277. $position = $tokens->findBlockEnd(
  55278. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  55279. $tokens->getNextTokenOfKind($position, ['('])
  55280. );
  55281. } elseif ($initialToken->isGivenKind(T_CLASS)) {
  55282. $openParenthesisPosition = $tokens->getNextMeaningfulToken($position);
  55283. if ('(' === $tokens[$openParenthesisPosition]->getContent()) {
  55284. $position = $tokens->findBlockEnd(
  55285. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  55286. $openParenthesisPosition
  55287. );
  55288. }
  55289. }
  55290. if ($initialToken->isGivenKind(T_FUNCTION)) {
  55291. $position = $tokens->getNextTokenOfKind($position, ['{']);
  55292. } else {
  55293. $position = $tokens->getNextMeaningfulToken($position);
  55294. }
  55295. if ('{' !== $tokens[$position]->getContent()) {
  55296. return $tokens->getNextTokenOfKind($position, [';']);
  55297. }
  55298. $position = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $position);
  55299. if ($initialToken->isGivenKind(T_DO)) {
  55300. $position = $tokens->findBlockEnd(
  55301. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  55302. $tokens->getNextTokenOfKind($position, ['('])
  55303. );
  55304. return $tokens->getNextTokenOfKind($position, [';']);
  55305. }
  55306. return $position;
  55307. }
  55308. }
  55309. <?php
  55310. declare(strict_types=1);
  55311. namespace PhpCsFixer\Fixer\FunctionNotation;
  55312. use PhpCsFixer\AbstractFixer;
  55313. use PhpCsFixer\FixerDefinition\CodeSample;
  55314. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55315. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55316. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  55317. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  55318. use PhpCsFixer\Tokenizer\Token;
  55319. use PhpCsFixer\Tokenizer\Tokens;
  55320. final class RegularCallableCallFixer extends AbstractFixer
  55321. {
  55322. public function getDefinition(): FixerDefinitionInterface
  55323. {
  55324. return new FixerDefinition(
  55325. 'Callables must be called without using `call_user_func*` when possible.',
  55326. [
  55327. new CodeSample(
  55328. '<?php
  55329. call_user_func("var_dump", 1, 2);
  55330. call_user_func("Bar\Baz::d", 1, 2);
  55331. call_user_func_array($callback, [1, 2]);
  55332. '
  55333. ),
  55334. new CodeSample(
  55335. '<?php
  55336. call_user_func(function ($a, $b) { var_dump($a, $b); }, 1, 2);
  55337. call_user_func(static function ($a, $b) { var_dump($a, $b); }, 1, 2);
  55338. '
  55339. ),
  55340. ],
  55341. null,
  55342. 'Risky when the `call_user_func` or `call_user_func_array` function is overridden or when are used in constructions that should be avoided, like `call_user_func_array(\'foo\', [\'bar\' => \'baz\'])` or `call_user_func($foo, $foo = \'bar\')`.'
  55343. );
  55344. }
  55345. public function getPriority(): int
  55346. {
  55347. return 2;
  55348. }
  55349. public function isCandidate(Tokens $tokens): bool
  55350. {
  55351. return $tokens->isTokenKindFound(T_STRING);
  55352. }
  55353. public function isRisky(): bool
  55354. {
  55355. return true;
  55356. }
  55357. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  55358. {
  55359. $functionsAnalyzer = new FunctionsAnalyzer();
  55360. $argumentsAnalyzer = new ArgumentsAnalyzer();
  55361. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  55362. if (!$tokens[$index]->equalsAny([[T_STRING, 'call_user_func'], [T_STRING, 'call_user_func_array']], false)) {
  55363. continue;
  55364. }
  55365. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  55366. continue;
  55367. }
  55368. $openParenthesis = $tokens->getNextMeaningfulToken($index);
  55369. $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
  55370. $arguments = $argumentsAnalyzer->getArguments($tokens, $openParenthesis, $closeParenthesis);
  55371. if (1 > \count($arguments)) {
  55372. return;
  55373. }
  55374. $this->processCall($tokens, $index, $arguments);
  55375. }
  55376. }
  55377. private function processCall(Tokens $tokens, int $index, array $arguments): void
  55378. {
  55379. $firstArgIndex = $tokens->getNextMeaningfulToken(
  55380. $tokens->getNextMeaningfulToken($index)
  55381. );
  55382. $firstArgToken = $tokens[$firstArgIndex];
  55383. if ($firstArgToken->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  55384. $afterFirstArgIndex = $tokens->getNextMeaningfulToken($firstArgIndex);
  55385. if (!$tokens[$afterFirstArgIndex]->equalsAny([',', ')'])) {
  55386. return;
  55387. }
  55388. $firstArgTokenContent = $firstArgToken->getContent();
  55389. if (!$this->isValidFunctionInvoke($firstArgTokenContent)) {
  55390. return;
  55391. }
  55392. $newCallTokens = Tokens::fromCode('<?php '.substr(str_replace('\\\\', '\\', $firstArgToken->getContent()), 1, -1).'();');
  55393. $newCallTokensSize = $newCallTokens->count();
  55394. $newCallTokens->clearAt(0);
  55395. $newCallTokens->clearRange($newCallTokensSize - 3, $newCallTokensSize - 1);
  55396. $newCallTokens->clearEmptyTokens();
  55397. $this->replaceCallUserFuncWithCallback($tokens, $index, $newCallTokens, $firstArgIndex, $firstArgIndex);
  55398. } elseif (
  55399. $firstArgToken->isGivenKind(T_FUNCTION)
  55400. || (
  55401. $firstArgToken->isGivenKind(T_STATIC)
  55402. && $tokens[$tokens->getNextMeaningfulToken($firstArgIndex)]->isGivenKind(T_FUNCTION)
  55403. )
  55404. ) {
  55405. $firstArgEndIndex = $tokens->findBlockEnd(
  55406. Tokens::BLOCK_TYPE_CURLY_BRACE,
  55407. $tokens->getNextTokenOfKind($firstArgIndex, ['{'])
  55408. );
  55409. $newCallTokens = $this->getTokensSubcollection($tokens, $firstArgIndex, $firstArgEndIndex);
  55410. $newCallTokens->insertAt($newCallTokens->count(), new Token(')'));
  55411. $newCallTokens->insertAt(0, new Token('('));
  55412. $this->replaceCallUserFuncWithCallback($tokens, $index, $newCallTokens, $firstArgIndex, $firstArgEndIndex);
  55413. } elseif ($firstArgToken->isGivenKind(T_VARIABLE)) {
  55414. $firstArgEndIndex = reset($arguments);
  55415. foreach ($arguments as $argumentStart => $argumentEnd) {
  55416. if ($firstArgEndIndex === $argumentEnd) {
  55417. continue;
  55418. }
  55419. for ($i = $argumentStart; $i <= $argumentEnd; ++$i) {
  55420. if ($tokens[$i]->equals($firstArgToken)) {
  55421. return;
  55422. }
  55423. }
  55424. }
  55425. $newCallTokens = $this->getTokensSubcollection($tokens, $firstArgIndex, $firstArgEndIndex);
  55426. $complex = false;
  55427. for ($newCallIndex = \count($newCallTokens) - 1; $newCallIndex >= 0; --$newCallIndex) {
  55428. if ($newCallTokens[$newCallIndex]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_VARIABLE])) {
  55429. continue;
  55430. }
  55431. $blockType = Tokens::detectBlockType($newCallTokens[$newCallIndex]);
  55432. if (null !== $blockType && (Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE === $blockType['type'] || Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE === $blockType['type'])) {
  55433. $newCallIndex = $newCallTokens->findBlockStart($blockType['type'], $newCallIndex);
  55434. continue;
  55435. }
  55436. $complex = true;
  55437. break;
  55438. }
  55439. if ($complex) {
  55440. $newCallTokens->insertAt($newCallTokens->count(), new Token(')'));
  55441. $newCallTokens->insertAt(0, new Token('('));
  55442. }
  55443. $this->replaceCallUserFuncWithCallback($tokens, $index, $newCallTokens, $firstArgIndex, $firstArgEndIndex);
  55444. }
  55445. }
  55446. private function replaceCallUserFuncWithCallback(Tokens $tokens, int $callIndex, Tokens $newCallTokens, int $firstArgStartIndex, int $firstArgEndIndex): void
  55447. {
  55448. $tokens->clearRange($firstArgStartIndex, $firstArgEndIndex);
  55449. $afterFirstArgIndex = $tokens->getNextMeaningfulToken($firstArgEndIndex);
  55450. $afterFirstArgToken = $tokens[$afterFirstArgIndex];
  55451. if ($afterFirstArgToken->equals(',')) {
  55452. $useEllipsis = $tokens[$callIndex]->equals([T_STRING, 'call_user_func_array'], false);
  55453. if ($useEllipsis) {
  55454. $secondArgIndex = $tokens->getNextMeaningfulToken($afterFirstArgIndex);
  55455. $tokens->insertAt($secondArgIndex, new Token([T_ELLIPSIS, '...']));
  55456. }
  55457. $tokens->clearAt($afterFirstArgIndex);
  55458. $tokens->removeTrailingWhitespace($afterFirstArgIndex);
  55459. }
  55460. $tokens->overrideRange($callIndex, $callIndex, $newCallTokens);
  55461. $prevIndex = $tokens->getPrevMeaningfulToken($callIndex);
  55462. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  55463. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  55464. }
  55465. }
  55466. private function getTokensSubcollection(Tokens $tokens, int $indexStart, int $indexEnd): Tokens
  55467. {
  55468. $size = $indexEnd - $indexStart + 1;
  55469. $subCollection = new Tokens($size);
  55470. for ($i = 0; $i < $size; ++$i) {
  55471. $toClone = $tokens[$i + $indexStart];
  55472. $subCollection[$i] = clone $toClone;
  55473. }
  55474. return $subCollection;
  55475. }
  55476. private function isValidFunctionInvoke(string $name): bool
  55477. {
  55478. if (\strlen($name) < 3 || 'b' === $name[0] || 'B' === $name[0]) {
  55479. return false;
  55480. }
  55481. $name = substr($name, 1, -1);
  55482. if ($name !== trim($name)) {
  55483. return false;
  55484. }
  55485. return true;
  55486. }
  55487. }
  55488. <?php
  55489. declare(strict_types=1);
  55490. namespace PhpCsFixer\Fixer\FunctionNotation;
  55491. use PhpCsFixer\AbstractFixer;
  55492. use PhpCsFixer\FixerDefinition\CodeSample;
  55493. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55494. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55495. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  55496. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  55497. use PhpCsFixer\Tokenizer\CT;
  55498. use PhpCsFixer\Tokenizer\Tokens;
  55499. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  55500. final class LambdaNotUsedImportFixer extends AbstractFixer
  55501. {
  55502. private ArgumentsAnalyzer $argumentsAnalyzer;
  55503. private FunctionsAnalyzer $functionAnalyzer;
  55504. private TokensAnalyzer $tokensAnalyzer;
  55505. public function getDefinition(): FixerDefinitionInterface
  55506. {
  55507. return new FixerDefinition(
  55508. 'Lambda must not import variables it doesn\'t use.',
  55509. [new CodeSample("<?php\n\$foo = function() use (\$bar) {};\n")]
  55510. );
  55511. }
  55512. public function getPriority(): int
  55513. {
  55514. return 31;
  55515. }
  55516. public function isCandidate(Tokens $tokens): bool
  55517. {
  55518. return $tokens->isAllTokenKindsFound([T_FUNCTION, CT::T_USE_LAMBDA]);
  55519. }
  55520. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  55521. {
  55522. $this->argumentsAnalyzer = new ArgumentsAnalyzer();
  55523. $this->functionAnalyzer = new FunctionsAnalyzer();
  55524. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  55525. for ($index = $tokens->count() - 4; $index > 0; --$index) {
  55526. $lambdaUseIndex = $this->getLambdaUseIndex($tokens, $index);
  55527. if (false !== $lambdaUseIndex) {
  55528. $this->fixLambda($tokens, $lambdaUseIndex);
  55529. }
  55530. }
  55531. }
  55532. private function fixLambda(Tokens $tokens, int $lambdaUseIndex): void
  55533. {
  55534. $lambdaUseOpenBraceIndex = $tokens->getNextTokenOfKind($lambdaUseIndex, ['(']);
  55535. $lambdaUseCloseBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $lambdaUseOpenBraceIndex);
  55536. $arguments = $this->argumentsAnalyzer->getArguments($tokens, $lambdaUseOpenBraceIndex, $lambdaUseCloseBraceIndex);
  55537. $imports = $this->filterArguments($tokens, $arguments);
  55538. if (0 === \count($imports)) {
  55539. return;
  55540. }
  55541. $notUsedImports = $this->findNotUsedLambdaImports($tokens, $imports, $lambdaUseCloseBraceIndex);
  55542. $notUsedImportsCount = \count($notUsedImports);
  55543. if (0 === $notUsedImportsCount) {
  55544. return;
  55545. }
  55546. if ($notUsedImportsCount === \count($arguments)) {
  55547. $this->clearImportsAndUse($tokens, $lambdaUseIndex, $lambdaUseCloseBraceIndex);
  55548. return;
  55549. }
  55550. $this->clearImports($tokens, array_reverse($notUsedImports));
  55551. }
  55552. private function findNotUsedLambdaImports(Tokens $tokens, array $imports, int $lambdaUseCloseBraceIndex): array
  55553. {
  55554. static $riskyKinds = [
  55555. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  55556. T_EVAL,
  55557. T_INCLUDE,
  55558. T_INCLUDE_ONCE,
  55559. T_REQUIRE,
  55560. T_REQUIRE_ONCE,
  55561. ];
  55562. $lambdaOpenIndex = $tokens->getNextTokenOfKind($lambdaUseCloseBraceIndex, ['{']);
  55563. $curlyBracesLevel = 0;
  55564. for ($index = $lambdaOpenIndex;; ++$index) {
  55565. $token = $tokens[$index];
  55566. if ($token->equals('{')) {
  55567. ++$curlyBracesLevel;
  55568. continue;
  55569. }
  55570. if ($token->equals('}')) {
  55571. --$curlyBracesLevel;
  55572. if (0 === $curlyBracesLevel) {
  55573. break;
  55574. }
  55575. continue;
  55576. }
  55577. if ($token->isGivenKind(T_STRING) && 'compact' === strtolower($token->getContent()) && $this->functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  55578. return [];
  55579. }
  55580. if ($token->isGivenKind($riskyKinds)) {
  55581. return [];
  55582. }
  55583. if ($token->equals('$')) {
  55584. $nextIndex = $tokens->getNextMeaningfulToken($index);
  55585. if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  55586. return [];
  55587. }
  55588. }
  55589. if ($token->isGivenKind(T_VARIABLE)) {
  55590. $content = $token->getContent();
  55591. if (isset($imports[$content])) {
  55592. unset($imports[$content]);
  55593. if (0 === \count($imports)) {
  55594. return $imports;
  55595. }
  55596. }
  55597. }
  55598. if ($token->isGivenKind(T_STRING_VARNAME)) {
  55599. $content = '$'.$token->getContent();
  55600. if (isset($imports[$content])) {
  55601. unset($imports[$content]);
  55602. if (0 === \count($imports)) {
  55603. return $imports;
  55604. }
  55605. }
  55606. }
  55607. if ($token->isClassy()) {
  55608. $index = $tokens->getNextTokenOfKind($index, ['(', '{']);
  55609. if ($tokens[$index]->equals('(')) {
  55610. $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  55611. $arguments = $this->argumentsAnalyzer->getArguments($tokens, $index, $closeBraceIndex);
  55612. $imports = $this->countImportsUsedAsArgument($tokens, $imports, $arguments);
  55613. $index = $tokens->getNextTokenOfKind($closeBraceIndex, ['{']);
  55614. }
  55615. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  55616. continue;
  55617. }
  55618. if ($token->isGivenKind(T_FUNCTION)) {
  55619. $lambdaUseOpenBraceIndex = $tokens->getNextTokenOfKind($index, ['(']);
  55620. $lambdaUseCloseBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $lambdaUseOpenBraceIndex);
  55621. $arguments = $this->argumentsAnalyzer->getArguments($tokens, $lambdaUseOpenBraceIndex, $lambdaUseCloseBraceIndex);
  55622. $imports = $this->countImportsUsedAsArgument($tokens, $imports, $arguments);
  55623. $index = $tokens->getNextTokenOfKind($index, [[CT::T_USE_LAMBDA], '{']);
  55624. if ($tokens[$index]->isGivenKind(CT::T_USE_LAMBDA)) {
  55625. $lambdaUseOpenBraceIndex = $tokens->getNextTokenOfKind($index, ['(']);
  55626. $lambdaUseCloseBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $lambdaUseOpenBraceIndex);
  55627. $arguments = $this->argumentsAnalyzer->getArguments($tokens, $lambdaUseOpenBraceIndex, $lambdaUseCloseBraceIndex);
  55628. $imports = $this->countImportsUsedAsArgument($tokens, $imports, $arguments);
  55629. $index = $tokens->getNextTokenOfKind($lambdaUseCloseBraceIndex, ['{']);
  55630. }
  55631. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  55632. continue;
  55633. }
  55634. }
  55635. return $imports;
  55636. }
  55637. private function countImportsUsedAsArgument(Tokens $tokens, array $imports, array $arguments): array
  55638. {
  55639. foreach ($arguments as $start => $end) {
  55640. $info = $this->argumentsAnalyzer->getArgumentInfo($tokens, $start, $end);
  55641. $content = $info->getName();
  55642. if (isset($imports[$content])) {
  55643. unset($imports[$content]);
  55644. if (0 === \count($imports)) {
  55645. return $imports;
  55646. }
  55647. }
  55648. }
  55649. return $imports;
  55650. }
  55651. private function getLambdaUseIndex(Tokens $tokens, int $index)
  55652. {
  55653. if (!$tokens[$index]->isGivenKind(T_FUNCTION) || !$this->tokensAnalyzer->isLambda($index)) {
  55654. return false;
  55655. }
  55656. $lambdaUseIndex = $tokens->getNextMeaningfulToken($index);
  55657. if ($tokens[$lambdaUseIndex]->isGivenKind(CT::T_RETURN_REF)) {
  55658. $lambdaUseIndex = $tokens->getNextMeaningfulToken($lambdaUseIndex);
  55659. }
  55660. $lambdaUseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $lambdaUseIndex);
  55661. $lambdaUseIndex = $tokens->getNextMeaningfulToken($lambdaUseIndex);
  55662. if (!$tokens[$lambdaUseIndex]->isGivenKind(CT::T_USE_LAMBDA)) {
  55663. return false;
  55664. }
  55665. return $lambdaUseIndex;
  55666. }
  55667. private function filterArguments(Tokens $tokens, array $arguments): array
  55668. {
  55669. $imports = [];
  55670. foreach ($arguments as $start => $end) {
  55671. $info = $this->argumentsAnalyzer->getArgumentInfo($tokens, $start, $end);
  55672. $argument = $info->getNameIndex();
  55673. if ($tokens[$tokens->getPrevMeaningfulToken($argument)]->equals('&')) {
  55674. continue;
  55675. }
  55676. $argumentCandidate = $tokens[$argument];
  55677. if ('$this' === $argumentCandidate->getContent()) {
  55678. continue;
  55679. }
  55680. if ($this->tokensAnalyzer->isSuperGlobal($argument)) {
  55681. continue;
  55682. }
  55683. $imports[$argumentCandidate->getContent()] = $argument;
  55684. }
  55685. return $imports;
  55686. }
  55687. private function clearImports(Tokens $tokens, array $imports): void
  55688. {
  55689. foreach ($imports as $removeIndex) {
  55690. $tokens->clearTokenAndMergeSurroundingWhitespace($removeIndex);
  55691. $previousRemoveIndex = $tokens->getPrevMeaningfulToken($removeIndex);
  55692. if ($tokens[$previousRemoveIndex]->equals(',')) {
  55693. $tokens->clearTokenAndMergeSurroundingWhitespace($previousRemoveIndex);
  55694. } elseif ($tokens[$previousRemoveIndex]->equals('(')) {
  55695. $tokens->clearTokenAndMergeSurroundingWhitespace($tokens->getNextMeaningfulToken($removeIndex));
  55696. }
  55697. }
  55698. }
  55699. private function clearImportsAndUse(Tokens $tokens, int $lambdaUseIndex, int $lambdaUseCloseBraceIndex): void
  55700. {
  55701. for ($i = $lambdaUseCloseBraceIndex; $i >= $lambdaUseIndex; --$i) {
  55702. if ($tokens[$i]->isComment()) {
  55703. continue;
  55704. }
  55705. if ($tokens[$i]->isWhitespace()) {
  55706. $previousIndex = $tokens->getPrevNonWhitespace($i);
  55707. if ($tokens[$previousIndex]->isComment()) {
  55708. continue;
  55709. }
  55710. }
  55711. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  55712. }
  55713. }
  55714. }
  55715. <?php
  55716. declare(strict_types=1);
  55717. namespace PhpCsFixer\Fixer\FunctionNotation;
  55718. use PhpCsFixer\AbstractFixer;
  55719. use PhpCsFixer\DocBlock\Annotation;
  55720. use PhpCsFixer\DocBlock\DocBlock;
  55721. use PhpCsFixer\FixerDefinition\CodeSample;
  55722. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55723. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55724. use PhpCsFixer\Tokenizer\CT;
  55725. use PhpCsFixer\Tokenizer\FCT;
  55726. use PhpCsFixer\Tokenizer\Token;
  55727. use PhpCsFixer\Tokenizer\Tokens;
  55728. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  55729. final class VoidReturnFixer extends AbstractFixer
  55730. {
  55731. private const PREVIOUS_TOKENS = [
  55732. T_ABSTRACT,
  55733. T_FINAL,
  55734. T_PRIVATE,
  55735. T_PROTECTED,
  55736. T_PUBLIC,
  55737. T_STATIC,
  55738. FCT::T_ATTRIBUTE,
  55739. ];
  55740. public function getDefinition(): FixerDefinitionInterface
  55741. {
  55742. return new FixerDefinition(
  55743. 'Add `void` return type to functions with missing or empty return statements, but priority is given to `@return` annotations.',
  55744. [
  55745. new CodeSample(
  55746. "<?php\nfunction foo(\$a) {};\n"
  55747. ),
  55748. ],
  55749. null,
  55750. 'Modifies the signature of functions.'
  55751. );
  55752. }
  55753. public function getPriority(): int
  55754. {
  55755. return 5;
  55756. }
  55757. public function isCandidate(Tokens $tokens): bool
  55758. {
  55759. return $tokens->isTokenKindFound(T_FUNCTION);
  55760. }
  55761. public function isRisky(): bool
  55762. {
  55763. return true;
  55764. }
  55765. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  55766. {
  55767. static $excludedFunctions = [
  55768. [T_STRING, '__clone'],
  55769. [T_STRING, '__construct'],
  55770. [T_STRING, '__debugInfo'],
  55771. [T_STRING, '__destruct'],
  55772. [T_STRING, '__isset'],
  55773. [T_STRING, '__serialize'],
  55774. [T_STRING, '__set_state'],
  55775. [T_STRING, '__sleep'],
  55776. [T_STRING, '__toString'],
  55777. ];
  55778. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  55779. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  55780. continue;
  55781. }
  55782. $functionName = $tokens->getNextMeaningfulToken($index);
  55783. if ($tokens[$functionName]->equalsAny($excludedFunctions, false)) {
  55784. continue;
  55785. }
  55786. $startIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  55787. if ($this->hasReturnTypeHint($tokens, $startIndex)) {
  55788. continue;
  55789. }
  55790. if ($tokens[$startIndex]->equals(';')) {
  55791. if ($this->hasVoidReturnAnnotation($tokens, $index)) {
  55792. $this->fixFunctionDefinition($tokens, $startIndex);
  55793. }
  55794. continue;
  55795. }
  55796. if ($this->hasReturnAnnotation($tokens, $index)) {
  55797. continue;
  55798. }
  55799. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  55800. if ($this->hasVoidReturn($tokens, $startIndex, $endIndex)) {
  55801. $this->fixFunctionDefinition($tokens, $startIndex);
  55802. }
  55803. }
  55804. }
  55805. private function hasReturnAnnotation(Tokens $tokens, int $index): bool
  55806. {
  55807. foreach ($this->findReturnAnnotations($tokens, $index) as $return) {
  55808. if (['void'] !== $return->getTypes()) {
  55809. return true;
  55810. }
  55811. }
  55812. return false;
  55813. }
  55814. private function hasVoidReturnAnnotation(Tokens $tokens, int $index): bool
  55815. {
  55816. foreach ($this->findReturnAnnotations($tokens, $index) as $return) {
  55817. if (['void'] === $return->getTypes()) {
  55818. return true;
  55819. }
  55820. }
  55821. return false;
  55822. }
  55823. private function hasReturnTypeHint(Tokens $tokens, int $index): bool
  55824. {
  55825. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  55826. $nextIndex = $tokens->getNextMeaningfulToken($endFuncIndex);
  55827. return $tokens[$nextIndex]->isGivenKind(CT::T_TYPE_COLON);
  55828. }
  55829. private function hasVoidReturn(Tokens $tokens, int $startIndex, int $endIndex): bool
  55830. {
  55831. $tokensAnalyzer = new TokensAnalyzer($tokens);
  55832. for ($i = $startIndex; $i < $endIndex; ++$i) {
  55833. if (
  55834. ($tokens[$i]->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($i))
  55835. || ($tokens[$i]->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($i))
  55836. ) {
  55837. $i = $tokens->getNextTokenOfKind($i, ['{']);
  55838. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  55839. continue;
  55840. }
  55841. if ($tokens[$i]->isGivenKind([T_YIELD, T_YIELD_FROM])) {
  55842. return false;
  55843. }
  55844. if (!$tokens[$i]->isGivenKind(T_RETURN)) {
  55845. continue;
  55846. }
  55847. $i = $tokens->getNextMeaningfulToken($i);
  55848. if (!$tokens[$i]->equals(';')) {
  55849. return false;
  55850. }
  55851. }
  55852. return true;
  55853. }
  55854. private function fixFunctionDefinition(Tokens $tokens, int $index): void
  55855. {
  55856. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  55857. $tokens->insertAt($endFuncIndex + 1, [
  55858. new Token([CT::T_TYPE_COLON, ':']),
  55859. new Token([T_WHITESPACE, ' ']),
  55860. new Token([T_STRING, 'void']),
  55861. ]);
  55862. }
  55863. private function findReturnAnnotations(Tokens $tokens, int $index): array
  55864. {
  55865. do {
  55866. $index = $tokens->getPrevNonWhitespace($index);
  55867. if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  55868. $index = $tokens->getPrevTokenOfKind($index, [[T_ATTRIBUTE]]);
  55869. }
  55870. } while ($tokens[$index]->isGivenKind(self::PREVIOUS_TOKENS));
  55871. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  55872. return [];
  55873. }
  55874. $doc = new DocBlock($tokens[$index]->getContent());
  55875. return $doc->getAnnotationsOfType('return');
  55876. }
  55877. }
  55878. <?php
  55879. declare(strict_types=1);
  55880. namespace PhpCsFixer\Fixer\FunctionNotation;
  55881. use PhpCsFixer\AbstractProxyFixer;
  55882. use PhpCsFixer\Fixer\Basic\NoTrailingCommaInSinglelineFixer;
  55883. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  55884. use PhpCsFixer\FixerDefinition\CodeSample;
  55885. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55886. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55887. final class NoTrailingCommaInSinglelineFunctionCallFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  55888. {
  55889. public function getDefinition(): FixerDefinitionInterface
  55890. {
  55891. return new FixerDefinition(
  55892. 'When making a method or function call on a single line there MUST NOT be a trailing comma after the last argument.',
  55893. [new CodeSample("<?php\nfoo(\$a,);\n")]
  55894. );
  55895. }
  55896. public function getPriority(): int
  55897. {
  55898. return 3;
  55899. }
  55900. public function getSuccessorsNames(): array
  55901. {
  55902. return array_keys($this->proxyFixers);
  55903. }
  55904. protected function createProxyFixers(): array
  55905. {
  55906. $fixer = new NoTrailingCommaInSinglelineFixer();
  55907. $fixer->configure(['elements' => ['arguments', 'array_destructuring']]);
  55908. return [$fixer];
  55909. }
  55910. }
  55911. <?php
  55912. declare(strict_types=1);
  55913. namespace PhpCsFixer\Fixer\FunctionNotation;
  55914. use PhpCsFixer\AbstractPhpdocToTypeDeclarationFixer;
  55915. use PhpCsFixer\DocBlock\Annotation;
  55916. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  55917. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  55918. use PhpCsFixer\FixerDefinition\CodeSample;
  55919. use PhpCsFixer\FixerDefinition\FixerDefinition;
  55920. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  55921. use PhpCsFixer\Tokenizer\Token;
  55922. use PhpCsFixer\Tokenizer\Tokens;
  55923. /**
  55924. @phpstan-import-type
  55925. @phpstan-type
  55926. @phpstan-type
  55927. @implements
  55928. */
  55929. final class PhpdocToPropertyTypeFixer extends AbstractPhpdocToTypeDeclarationFixer implements ConfigurableFixerInterface, ExperimentalFixerInterface
  55930. {
  55931. private const TYPE_CHECK_TEMPLATE = '<?php class A { private %s $b; }';
  55932. private array $skippedTypes = [
  55933. 'resource' => true,
  55934. 'null' => true,
  55935. ];
  55936. public function getDefinition(): FixerDefinitionInterface
  55937. {
  55938. return new FixerDefinition(
  55939. 'Takes `@var` annotation of non-mixed types and adjusts accordingly the property signature..',
  55940. [
  55941. new CodeSample(
  55942. '<?php
  55943. class Foo {
  55944. /** @var int */
  55945. private $foo;
  55946. /** @var \Traversable */
  55947. private $bar;
  55948. }
  55949. ',
  55950. ),
  55951. new CodeSample(
  55952. '<?php
  55953. class Foo {
  55954. /** @var int */
  55955. private $foo;
  55956. /** @var \Traversable */
  55957. private $bar;
  55958. }
  55959. ',
  55960. ['scalar_types' => false]
  55961. ),
  55962. new CodeSample(
  55963. '<?php
  55964. class Foo {
  55965. /** @var int|string */
  55966. private $foo;
  55967. /** @var \Traversable */
  55968. private $bar;
  55969. }
  55970. ',
  55971. ['union_types' => false]
  55972. ),
  55973. ],
  55974. null,
  55975. 'The `@var` annotation is mandatory for the fixer to make changes, signatures of properties without it (no docblock) will not be fixed. Manual actions might be required for newly typed properties that are read before initialization.'
  55976. );
  55977. }
  55978. public function isCandidate(Tokens $tokens): bool
  55979. {
  55980. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  55981. }
  55982. public function getPriority(): int
  55983. {
  55984. return 8;
  55985. }
  55986. protected function isSkippedType(string $type): bool
  55987. {
  55988. return isset($this->skippedTypes[$type]);
  55989. }
  55990. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  55991. {
  55992. for ($index = $tokens->count() - 1; 0 < $index; --$index) {
  55993. if ($tokens[$index]->isGivenKind([T_CLASS, T_TRAIT])) {
  55994. $this->fixClass($tokens, $index);
  55995. }
  55996. }
  55997. }
  55998. protected function createTokensFromRawType(string $type): Tokens
  55999. {
  56000. $typeTokens = Tokens::fromCode(\sprintf(self::TYPE_CHECK_TEMPLATE, $type));
  56001. $typeTokens->clearRange(0, 8);
  56002. $typeTokens->clearRange(\count($typeTokens) - 5, \count($typeTokens) - 1);
  56003. $typeTokens->clearEmptyTokens();
  56004. return $typeTokens;
  56005. }
  56006. private function fixClass(Tokens $tokens, int $index): void
  56007. {
  56008. $index = $tokens->getNextTokenOfKind($index, ['{']);
  56009. $classEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  56010. for (; $index < $classEndIndex; ++$index) {
  56011. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  56012. $index = $tokens->getNextTokenOfKind($index, ['{', ';']);
  56013. if ($tokens[$index]->equals('{')) {
  56014. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  56015. }
  56016. continue;
  56017. }
  56018. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  56019. continue;
  56020. }
  56021. $docCommentIndex = $index;
  56022. $propertyIndices = $this->findNextUntypedPropertiesDeclaration($tokens, $docCommentIndex);
  56023. if ([] === $propertyIndices) {
  56024. continue;
  56025. }
  56026. $typeInfo = $this->resolveApplicableType(
  56027. $propertyIndices,
  56028. $this->getAnnotationsFromDocComment('var', $tokens, $docCommentIndex)
  56029. );
  56030. if (null === $typeInfo) {
  56031. continue;
  56032. }
  56033. $propertyType = $typeInfo['commonType'];
  56034. $isNullable = $typeInfo['isNullable'];
  56035. if (\in_array($propertyType, ['callable', 'never', 'void'], true)) {
  56036. continue;
  56037. }
  56038. if (!$this->isValidSyntax(\sprintf(self::TYPE_CHECK_TEMPLATE, $propertyType))) {
  56039. continue;
  56040. }
  56041. $newTokens = array_merge(
  56042. $this->createTypeDeclarationTokens($propertyType, $isNullable),
  56043. [new Token([T_WHITESPACE, ' '])]
  56044. );
  56045. $tokens->insertAt(current($propertyIndices), $newTokens);
  56046. $index = max($propertyIndices) + \count($newTokens) + 1;
  56047. $classEndIndex += \count($newTokens);
  56048. }
  56049. }
  56050. private function findNextUntypedPropertiesDeclaration(Tokens $tokens, int $index): array
  56051. {
  56052. do {
  56053. $index = $tokens->getNextMeaningfulToken($index);
  56054. } while ($tokens[$index]->isGivenKind([
  56055. T_PRIVATE,
  56056. T_PROTECTED,
  56057. T_PUBLIC,
  56058. T_STATIC,
  56059. T_VAR,
  56060. ]));
  56061. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  56062. return [];
  56063. }
  56064. $properties = [];
  56065. while (!$tokens[$index]->equals(';')) {
  56066. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  56067. $properties[$tokens[$index]->getContent()] = $index;
  56068. }
  56069. $index = $tokens->getNextMeaningfulToken($index);
  56070. }
  56071. return $properties;
  56072. }
  56073. private function resolveApplicableType(array $propertyIndices, array $annotations): ?array
  56074. {
  56075. $propertyTypes = [];
  56076. foreach ($annotations as $annotation) {
  56077. $propertyName = $annotation->getVariableName();
  56078. if (null === $propertyName) {
  56079. if (1 !== \count($propertyIndices)) {
  56080. continue;
  56081. }
  56082. $propertyName = array_key_first($propertyIndices);
  56083. }
  56084. if (!isset($propertyIndices[$propertyName])) {
  56085. continue;
  56086. }
  56087. $typesExpression = $annotation->getTypeExpression();
  56088. if (null === $typesExpression) {
  56089. continue;
  56090. }
  56091. $typeInfo = $this->getCommonTypeInfo($typesExpression, false);
  56092. $unionTypes = null;
  56093. if (null === $typeInfo) {
  56094. $unionTypes = $this->getUnionTypes($typesExpression, false);
  56095. }
  56096. if (null === $typeInfo && null === $unionTypes) {
  56097. continue;
  56098. }
  56099. if (null !== $unionTypes) {
  56100. $typeInfo = ['commonType' => $unionTypes, 'isNullable' => false];
  56101. }
  56102. if (\array_key_exists($propertyName, $propertyTypes) && $typeInfo !== $propertyTypes[$propertyName]) {
  56103. return null;
  56104. }
  56105. $propertyTypes[$propertyName] = $typeInfo;
  56106. }
  56107. if (\count($propertyTypes) !== \count($propertyIndices)) {
  56108. return null;
  56109. }
  56110. $type = array_shift($propertyTypes);
  56111. foreach ($propertyTypes as $propertyType) {
  56112. if ($propertyType !== $type) {
  56113. return null;
  56114. }
  56115. }
  56116. return $type;
  56117. }
  56118. }
  56119. <?php
  56120. declare(strict_types=1);
  56121. namespace PhpCsFixer\Fixer\FunctionNotation;
  56122. use PhpCsFixer\AbstractFixer;
  56123. use PhpCsFixer\FixerDefinition\CodeSample;
  56124. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56125. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56126. use PhpCsFixer\Tokenizer\CT;
  56127. use PhpCsFixer\Tokenizer\Token;
  56128. use PhpCsFixer\Tokenizer\Tokens;
  56129. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  56130. final class StaticLambdaFixer extends AbstractFixer
  56131. {
  56132. public function getDefinition(): FixerDefinitionInterface
  56133. {
  56134. return new FixerDefinition(
  56135. 'Lambdas not (indirectly) referencing `$this` must be declared `static`.',
  56136. [new CodeSample("<?php\n\$a = function () use (\$b)\n{ echo \$b;\n};\n")],
  56137. null,
  56138. 'Risky when using `->bindTo` on lambdas without referencing to `$this`.'
  56139. );
  56140. }
  56141. public function isCandidate(Tokens $tokens): bool
  56142. {
  56143. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  56144. }
  56145. public function isRisky(): bool
  56146. {
  56147. return true;
  56148. }
  56149. public function getPriority(): int
  56150. {
  56151. return parent::getPriority();
  56152. }
  56153. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  56154. {
  56155. $analyzer = new TokensAnalyzer($tokens);
  56156. $expectedFunctionKinds = [T_FUNCTION, T_FN];
  56157. for ($index = $tokens->count() - 4; $index > 0; --$index) {
  56158. if (!$tokens[$index]->isGivenKind($expectedFunctionKinds) || !$analyzer->isLambda($index)) {
  56159. continue;
  56160. }
  56161. $prev = $tokens->getPrevMeaningfulToken($index);
  56162. if ($tokens[$prev]->isGivenKind(T_STATIC)) {
  56163. continue;
  56164. }
  56165. $argumentsStartIndex = $tokens->getNextTokenOfKind($index, ['(']);
  56166. $argumentsEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStartIndex);
  56167. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  56168. $lambdaOpenIndex = $tokens->getNextTokenOfKind($argumentsEndIndex, ['{']);
  56169. $lambdaEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $lambdaOpenIndex);
  56170. } else {
  56171. $lambdaOpenIndex = $tokens->getNextTokenOfKind($argumentsEndIndex, [[T_DOUBLE_ARROW]]);
  56172. $lambdaEndIndex = $analyzer->getLastTokenIndexOfArrowFunction($index);
  56173. }
  56174. if ($this->hasPossibleReferenceToThis($tokens, $lambdaOpenIndex, $lambdaEndIndex)) {
  56175. continue;
  56176. }
  56177. $tokens->insertAt(
  56178. $index,
  56179. [
  56180. new Token([T_STATIC, 'static']),
  56181. new Token([T_WHITESPACE, ' ']),
  56182. ]
  56183. );
  56184. $index -= 4;
  56185. }
  56186. }
  56187. private function hasPossibleReferenceToThis(Tokens $tokens, int $startIndex, int $endIndex): bool
  56188. {
  56189. for ($i = $startIndex; $i <= $endIndex; ++$i) {
  56190. if ($tokens[$i]->isGivenKind(T_VARIABLE) && '$this' === strtolower($tokens[$i]->getContent())) {
  56191. return true;
  56192. }
  56193. if ($tokens[$i]->isGivenKind([
  56194. T_INCLUDE,
  56195. T_INCLUDE_ONCE,
  56196. T_REQUIRE,
  56197. T_REQUIRE_ONCE,
  56198. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  56199. T_EVAL,
  56200. ])) {
  56201. return true;
  56202. }
  56203. if ($tokens[$i]->isClassy()) {
  56204. $openBraceIndex = $tokens->getNextTokenOfKind($i, ['{']);
  56205. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openBraceIndex);
  56206. continue;
  56207. }
  56208. if ($tokens[$i]->equals('$')) {
  56209. $nextIndex = $tokens->getNextMeaningfulToken($i);
  56210. if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  56211. return true;
  56212. }
  56213. }
  56214. if ($tokens[$i]->equals([T_STRING, 'parent'], false)) {
  56215. return true;
  56216. }
  56217. }
  56218. return false;
  56219. }
  56220. }
  56221. <?php
  56222. declare(strict_types=1);
  56223. namespace PhpCsFixer\Fixer\FunctionNotation;
  56224. use PhpCsFixer\AbstractFixer;
  56225. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  56226. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  56227. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  56228. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  56229. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  56230. use PhpCsFixer\FixerDefinition\CodeSample;
  56231. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56232. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56233. use PhpCsFixer\Tokenizer\CT;
  56234. use PhpCsFixer\Tokenizer\Token;
  56235. use PhpCsFixer\Tokenizer\Tokens;
  56236. /**
  56237. @phpstan-type
  56238. @phpstan-type
  56239. @implements
  56240. */
  56241. final class ReturnTypeDeclarationFixer extends AbstractFixer implements ConfigurableFixerInterface
  56242. {
  56243. /**
  56244. @use */
  56245. use ConfigurableFixerTrait;
  56246. public function getDefinition(): FixerDefinitionInterface
  56247. {
  56248. return new FixerDefinition(
  56249. 'Adjust spacing around colon in return type declarations and backed enum types.',
  56250. [
  56251. new CodeSample(
  56252. "<?php\nfunction foo(int \$a):string {};\n"
  56253. ),
  56254. new CodeSample(
  56255. "<?php\nfunction foo(int \$a):string {};\n",
  56256. ['space_before' => 'none']
  56257. ),
  56258. new CodeSample(
  56259. "<?php\nfunction foo(int \$a):string {};\n",
  56260. ['space_before' => 'one']
  56261. ),
  56262. ],
  56263. 'Rule is applied only in a PHP 7+ environment.'
  56264. );
  56265. }
  56266. public function getPriority(): int
  56267. {
  56268. return -17;
  56269. }
  56270. public function isCandidate(Tokens $tokens): bool
  56271. {
  56272. return $tokens->isTokenKindFound(CT::T_TYPE_COLON);
  56273. }
  56274. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  56275. {
  56276. $oneSpaceBefore = 'one' === $this->configuration['space_before'];
  56277. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  56278. if (!$tokens[$index]->isGivenKind(CT::T_TYPE_COLON)) {
  56279. continue;
  56280. }
  56281. $previousIndex = $index - 1;
  56282. $previousToken = $tokens[$previousIndex];
  56283. if ($previousToken->isWhitespace()) {
  56284. if (!$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  56285. if ($oneSpaceBefore) {
  56286. $tokens[$previousIndex] = new Token([T_WHITESPACE, ' ']);
  56287. } else {
  56288. $tokens->clearAt($previousIndex);
  56289. }
  56290. }
  56291. } elseif ($oneSpaceBefore) {
  56292. $tokenWasAdded = $tokens->ensureWhitespaceAtIndex($index, 0, ' ');
  56293. if ($tokenWasAdded) {
  56294. ++$limit;
  56295. }
  56296. ++$index;
  56297. }
  56298. ++$index;
  56299. $tokenWasAdded = $tokens->ensureWhitespaceAtIndex($index, 0, ' ');
  56300. if ($tokenWasAdded) {
  56301. ++$limit;
  56302. }
  56303. }
  56304. }
  56305. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  56306. {
  56307. return new FixerConfigurationResolver([
  56308. (new FixerOptionBuilder('space_before', 'Spacing to apply before colon.'))
  56309. ->setAllowedValues(['one', 'none'])
  56310. ->setDefault('none')
  56311. ->getOption(),
  56312. ]);
  56313. }
  56314. }
  56315. <?php
  56316. declare(strict_types=1);
  56317. namespace PhpCsFixer\Fixer\FunctionNotation;
  56318. use PhpCsFixer\AbstractProxyFixer;
  56319. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  56320. use PhpCsFixer\Fixer\Whitespace\TypeDeclarationSpacesFixer;
  56321. use PhpCsFixer\FixerDefinition\CodeSample;
  56322. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56323. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56324. use PhpCsFixer\Tokenizer\Tokens;
  56325. final class FunctionTypehintSpaceFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  56326. {
  56327. public function getDefinition(): FixerDefinitionInterface
  56328. {
  56329. return new FixerDefinition(
  56330. 'Ensure single space between function\'s argument and its typehint.',
  56331. [
  56332. new CodeSample("<?php\nfunction sample(array\$a)\n{}\n"),
  56333. new CodeSample("<?php\nfunction sample(array \$a)\n{}\n"),
  56334. ]
  56335. );
  56336. }
  56337. public function isCandidate(Tokens $tokens): bool
  56338. {
  56339. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  56340. }
  56341. public function getSuccessorsNames(): array
  56342. {
  56343. return array_keys($this->proxyFixers);
  56344. }
  56345. protected function createProxyFixers(): array
  56346. {
  56347. $fixer = new TypeDeclarationSpacesFixer();
  56348. $fixer->configure(['elements' => ['function']]);
  56349. return [$fixer];
  56350. }
  56351. }
  56352. <?php
  56353. declare(strict_types=1);
  56354. namespace PhpCsFixer\Fixer\FunctionNotation;
  56355. use PhpCsFixer\AbstractFixer;
  56356. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  56357. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  56358. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  56359. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  56360. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  56361. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  56362. use PhpCsFixer\FixerDefinition\CodeSample;
  56363. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56364. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56365. use PhpCsFixer\Preg;
  56366. use PhpCsFixer\Tokenizer\CT;
  56367. use PhpCsFixer\Tokenizer\Token;
  56368. use PhpCsFixer\Tokenizer\Tokens;
  56369. /**
  56370. @phpstan-type
  56371. @phpstan-type
  56372. @implements
  56373. */
  56374. final class MethodArgumentSpaceFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  56375. {
  56376. /**
  56377. @use */
  56378. use ConfigurableFixerTrait;
  56379. public function getDefinition(): FixerDefinitionInterface
  56380. {
  56381. return new FixerDefinition(
  56382. 'In method arguments and method call, there MUST NOT be a space before each comma and there MUST be one space after each comma. Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.',
  56383. [
  56384. new CodeSample(
  56385. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  56386. null
  56387. ),
  56388. new CodeSample(
  56389. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  56390. ['keep_multiple_spaces_after_comma' => false]
  56391. ),
  56392. new CodeSample(
  56393. "<?php\nfunction sample(\$a=10,\$b=20,\$c=30) {}\nsample(1, 2);\n",
  56394. ['keep_multiple_spaces_after_comma' => true]
  56395. ),
  56396. new CodeSample(
  56397. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1,\n 2);\n",
  56398. ['on_multiline' => 'ensure_fully_multiline']
  56399. ),
  56400. new CodeSample(
  56401. "<?php\nfunction sample(\n \$a=10,\n \$b=20,\n \$c=30\n) {}\nsample(\n 1,\n 2\n);\n",
  56402. ['on_multiline' => 'ensure_single_line']
  56403. ),
  56404. new CodeSample(
  56405. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1, \n 2);\nsample('foo', 'foobarbaz', 'baz');\nsample('foobar', 'bar', 'baz');\n",
  56406. [
  56407. 'on_multiline' => 'ensure_fully_multiline',
  56408. 'keep_multiple_spaces_after_comma' => true,
  56409. ]
  56410. ),
  56411. new CodeSample(
  56412. "<?php\nfunction sample(\$a=10,\n \$b=20,\$c=30) {}\nsample(1, \n 2);\nsample('foo', 'foobarbaz', 'baz');\nsample('foobar', 'bar', 'baz');\n",
  56413. [
  56414. 'on_multiline' => 'ensure_fully_multiline',
  56415. 'keep_multiple_spaces_after_comma' => false,
  56416. ]
  56417. ),
  56418. new CodeSample(
  56419. "<?php\nfunction sample(#[Foo] #[Bar] \$a=10,\n \$b=20,\$c=30) {}\nsample(1, 2);\n",
  56420. [
  56421. 'on_multiline' => 'ensure_fully_multiline',
  56422. 'attribute_placement' => 'ignore',
  56423. ]
  56424. ),
  56425. new CodeSample(
  56426. "<?php\nfunction sample(#[Foo]\n #[Bar]\n \$a=10,\n \$b=20,\$c=30) {}\nsample(1, 2);\n",
  56427. [
  56428. 'on_multiline' => 'ensure_fully_multiline',
  56429. 'attribute_placement' => 'same_line',
  56430. ]
  56431. ),
  56432. new CodeSample(
  56433. "<?php\nfunction sample(#[Foo] #[Bar] \$a=10,\n \$b=20,\$c=30) {}\nsample(1, 2);\n",
  56434. [
  56435. 'on_multiline' => 'ensure_fully_multiline',
  56436. 'attribute_placement' => 'standalone',
  56437. ]
  56438. ),
  56439. new CodeSample(
  56440. <<<'SAMPLE'
  56441. <?php
  56442. sample(
  56443. <<<EOD
  56444. foo
  56445. EOD
  56446. ,
  56447. 'bar'
  56448. );
  56449. SAMPLE
  56450. ,
  56451. ['after_heredoc' => true]
  56452. ),
  56453. ],
  56454. 'This fixer covers rules defined in PSR2 ¶4.4, ¶4.6.'
  56455. );
  56456. }
  56457. public function isCandidate(Tokens $tokens): bool
  56458. {
  56459. return $tokens->isTokenKindFound('(');
  56460. }
  56461. public function getPriority(): int
  56462. {
  56463. return 30;
  56464. }
  56465. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  56466. {
  56467. $expectedTokens = [T_LIST, T_FUNCTION, CT::T_USE_LAMBDA, T_FN, T_CLASS];
  56468. $tokenCount = $tokens->count();
  56469. for ($index = 1; $index < $tokenCount; ++$index) {
  56470. $token = $tokens[$index];
  56471. if (!$token->equals('(')) {
  56472. continue;
  56473. }
  56474. $meaningfulTokenBeforeParenthesis = $tokens[$tokens->getPrevMeaningfulToken($index)];
  56475. if (
  56476. $meaningfulTokenBeforeParenthesis->isKeyword()
  56477. && !$meaningfulTokenBeforeParenthesis->isGivenKind($expectedTokens)
  56478. ) {
  56479. continue;
  56480. }
  56481. $isMultiline = $this->fixFunction($tokens, $index);
  56482. if (
  56483. $isMultiline
  56484. && 'ensure_fully_multiline' === $this->configuration['on_multiline']
  56485. && !$meaningfulTokenBeforeParenthesis->isGivenKind(T_LIST)
  56486. ) {
  56487. $this->ensureFunctionFullyMultiline($tokens, $index);
  56488. }
  56489. }
  56490. }
  56491. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  56492. {
  56493. return new FixerConfigurationResolver([
  56494. (new FixerOptionBuilder('keep_multiple_spaces_after_comma', 'Whether keep multiple spaces after comma.'))
  56495. ->setAllowedTypes(['bool'])
  56496. ->setDefault(false)
  56497. ->getOption(),
  56498. (new FixerOptionBuilder(
  56499. 'on_multiline',
  56500. 'Defines how to handle function arguments lists that contain newlines.'
  56501. ))
  56502. ->setAllowedValues(['ignore', 'ensure_single_line', 'ensure_fully_multiline'])
  56503. ->setDefault('ensure_fully_multiline')
  56504. ->getOption(),
  56505. (new FixerOptionBuilder('after_heredoc', 'Whether the whitespace between heredoc end and comma should be removed.'))
  56506. ->setAllowedTypes(['bool'])
  56507. ->setDefault(false)
  56508. ->getOption(),
  56509. (new FixerOptionBuilder(
  56510. 'attribute_placement',
  56511. 'Defines how to handle argument attributes when function definition is multiline.'
  56512. ))
  56513. ->setAllowedValues(['ignore', 'same_line', 'standalone'])
  56514. ->setDefault('standalone')
  56515. ->getOption(),
  56516. ]);
  56517. }
  56518. private function fixFunction(Tokens $tokens, int $startFunctionIndex): bool
  56519. {
  56520. $isMultiline = false;
  56521. $endFunctionIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startFunctionIndex);
  56522. $firstWhitespaceIndex = $this->findWhitespaceIndexAfterParenthesis($tokens, $startFunctionIndex, $endFunctionIndex);
  56523. $lastWhitespaceIndex = $this->findWhitespaceIndexAfterParenthesis($tokens, $endFunctionIndex, $startFunctionIndex);
  56524. foreach ([$firstWhitespaceIndex, $lastWhitespaceIndex] as $index) {
  56525. if (null === $index || !Preg::match('/\R/', $tokens[$index]->getContent())) {
  56526. continue;
  56527. }
  56528. if ('ensure_single_line' !== $this->configuration['on_multiline']) {
  56529. $isMultiline = true;
  56530. continue;
  56531. }
  56532. $newLinesRemoved = $this->ensureSingleLine($tokens, $index);
  56533. if (!$newLinesRemoved) {
  56534. $isMultiline = true;
  56535. }
  56536. }
  56537. for ($index = $endFunctionIndex - 1; $index > $startFunctionIndex; --$index) {
  56538. $token = $tokens[$index];
  56539. if ($token->equals(')')) {
  56540. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  56541. continue;
  56542. }
  56543. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  56544. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  56545. continue;
  56546. }
  56547. if ($token->equals('}')) {
  56548. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  56549. continue;
  56550. }
  56551. if ($token->equals(',')) {
  56552. $this->fixSpace($tokens, $index);
  56553. if (!$isMultiline && $this->isNewline($tokens[$index + 1])) {
  56554. $isMultiline = true;
  56555. }
  56556. }
  56557. }
  56558. return $isMultiline;
  56559. }
  56560. private function findWhitespaceIndexAfterParenthesis(Tokens $tokens, int $startParenthesisIndex, int $endParenthesisIndex): ?int
  56561. {
  56562. $direction = $endParenthesisIndex > $startParenthesisIndex ? 1 : -1;
  56563. $startIndex = $startParenthesisIndex + $direction;
  56564. $endIndex = $endParenthesisIndex - $direction;
  56565. for ($index = $startIndex; $index !== $endIndex; $index += $direction) {
  56566. $token = $tokens[$index];
  56567. if ($token->isWhitespace()) {
  56568. return $index;
  56569. }
  56570. if (!$token->isComment()) {
  56571. break;
  56572. }
  56573. }
  56574. return null;
  56575. }
  56576. private function ensureSingleLine(Tokens $tokens, int $index): bool
  56577. {
  56578. $previousToken = $tokens[$index - 1];
  56579. if ($previousToken->isComment() && !str_starts_with($previousToken->getContent(), '/*')) {
  56580. return false;
  56581. }
  56582. $content = Preg::replace('/\R\h*/', '', $tokens[$index]->getContent());
  56583. $tokens->ensureWhitespaceAtIndex($index, 0, $content);
  56584. return true;
  56585. }
  56586. private function ensureFunctionFullyMultiline(Tokens $tokens, int $startFunctionIndex): void
  56587. {
  56588. $searchIndex = $startFunctionIndex;
  56589. do {
  56590. $prevWhitespaceTokenIndex = $tokens->getPrevTokenOfKind(
  56591. $searchIndex,
  56592. [[T_ENCAPSED_AND_WHITESPACE], [T_INLINE_HTML], [T_WHITESPACE]],
  56593. );
  56594. $searchIndex = $prevWhitespaceTokenIndex;
  56595. } while (null !== $prevWhitespaceTokenIndex
  56596. && !str_contains($tokens[$prevWhitespaceTokenIndex]->getContent(), "\n")
  56597. );
  56598. if (null === $prevWhitespaceTokenIndex) {
  56599. $existingIndentation = '';
  56600. } elseif (!$tokens[$prevWhitespaceTokenIndex]->isGivenKind(T_WHITESPACE)) {
  56601. return;
  56602. } else {
  56603. $existingIndentation = $tokens[$prevWhitespaceTokenIndex]->getContent();
  56604. $lastLineIndex = strrpos($existingIndentation, "\n");
  56605. $existingIndentation = false === $lastLineIndex
  56606. ? $existingIndentation
  56607. : substr($existingIndentation, $lastLineIndex + 1);
  56608. }
  56609. $indentation = $existingIndentation.$this->whitespacesConfig->getIndent();
  56610. $endFunctionIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startFunctionIndex);
  56611. $wasWhitespaceBeforeEndFunctionAddedAsNewToken = $tokens->ensureWhitespaceAtIndex(
  56612. $tokens[$endFunctionIndex - 1]->isWhitespace() ? $endFunctionIndex - 1 : $endFunctionIndex,
  56613. 0,
  56614. $this->whitespacesConfig->getLineEnding().$existingIndentation
  56615. );
  56616. if ($wasWhitespaceBeforeEndFunctionAddedAsNewToken) {
  56617. ++$endFunctionIndex;
  56618. }
  56619. for ($index = $endFunctionIndex - 1; $index > $startFunctionIndex; --$index) {
  56620. $token = $tokens[$index];
  56621. if ($token->equals(')')) {
  56622. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  56623. continue;
  56624. }
  56625. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) {
  56626. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  56627. continue;
  56628. }
  56629. if ($token->equals('}')) {
  56630. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  56631. continue;
  56632. }
  56633. if ($tokens[$tokens->getNextMeaningfulToken($index)]->equals(')')) {
  56634. continue;
  56635. }
  56636. if ($token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  56637. if ('standalone' === $this->configuration['attribute_placement']) {
  56638. $this->fixNewline($tokens, $index, $indentation);
  56639. } elseif ('same_line' === $this->configuration['attribute_placement']) {
  56640. $this->ensureSingleLine($tokens, $index + 1);
  56641. $tokens->ensureWhitespaceAtIndex($index + 1, 0, ' ');
  56642. }
  56643. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  56644. continue;
  56645. }
  56646. if ($token->equals(',')) {
  56647. $this->fixNewline($tokens, $index, $indentation);
  56648. }
  56649. }
  56650. $this->fixNewline($tokens, $startFunctionIndex, $indentation, false);
  56651. }
  56652. private function fixNewline(Tokens $tokens, int $index, string $indentation, bool $override = true): void
  56653. {
  56654. if ($tokens[$index + 1]->isComment()) {
  56655. return;
  56656. }
  56657. if ($tokens[$index + 2]->isComment()) {
  56658. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index + 2);
  56659. if (!$this->isNewline($tokens[$nextMeaningfulTokenIndex - 1])) {
  56660. if ($tokens[$nextMeaningfulTokenIndex - 1]->isWhitespace()) {
  56661. $tokens->clearAt($nextMeaningfulTokenIndex - 1);
  56662. }
  56663. $tokens->ensureWhitespaceAtIndex($nextMeaningfulTokenIndex, 0, $this->whitespacesConfig->getLineEnding().$indentation);
  56664. }
  56665. return;
  56666. }
  56667. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index);
  56668. if ($tokens[$nextMeaningfulTokenIndex]->equals(')')) {
  56669. return;
  56670. }
  56671. $tokens->ensureWhitespaceAtIndex($index + 1, 0, $this->whitespacesConfig->getLineEnding().$indentation);
  56672. }
  56673. private function fixSpace(Tokens $tokens, int $index): void
  56674. {
  56675. if ($tokens[$index - 1]->isWhitespace()) {
  56676. $prevIndex = $tokens->getPrevNonWhitespace($index - 1);
  56677. if (
  56678. !$tokens[$prevIndex]->equals(',') && !$tokens[$prevIndex]->isComment()
  56679. && (true === $this->configuration['after_heredoc'] || !$tokens[$prevIndex]->isGivenKind(T_END_HEREDOC))
  56680. ) {
  56681. $tokens->clearAt($index - 1);
  56682. }
  56683. }
  56684. $nextIndex = $index + 1;
  56685. $nextToken = $tokens[$nextIndex];
  56686. if ($nextToken->isWhitespace()) {
  56687. $newContent = $nextToken->getContent();
  56688. if ('ensure_single_line' === $this->configuration['on_multiline']) {
  56689. $newContent = Preg::replace('/\R/', '', $newContent);
  56690. }
  56691. if (
  56692. (false === $this->configuration['keep_multiple_spaces_after_comma'] || Preg::match('/\R/', $newContent))
  56693. && !$this->isCommentLastLineToken($tokens, $index + 2)
  56694. ) {
  56695. $newContent = ltrim($newContent, " \t");
  56696. }
  56697. $tokens[$nextIndex] = new Token([T_WHITESPACE, '' === $newContent ? ' ' : $newContent]);
  56698. return;
  56699. }
  56700. if (!$this->isCommentLastLineToken($tokens, $index + 1)) {
  56701. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  56702. }
  56703. }
  56704. private function isCommentLastLineToken(Tokens $tokens, int $index): bool
  56705. {
  56706. if (!$tokens[$index]->isComment() || !$tokens[$index + 1]->isWhitespace()) {
  56707. return false;
  56708. }
  56709. $content = $tokens[$index + 1]->getContent();
  56710. return $content !== ltrim($content, "\r\n");
  56711. }
  56712. private function isNewline(Token $token): bool
  56713. {
  56714. return $token->isWhitespace() && str_contains($token->getContent(), "\n");
  56715. }
  56716. }
  56717. <?php
  56718. declare(strict_types=1);
  56719. namespace PhpCsFixer\Fixer\FunctionNotation;
  56720. use PhpCsFixer\AbstractFixer;
  56721. use PhpCsFixer\FixerDefinition\CodeSample;
  56722. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56723. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56724. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  56725. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  56726. use PhpCsFixer\Tokenizer\Token;
  56727. use PhpCsFixer\Tokenizer\Tokens;
  56728. final class DateTimeCreateFromFormatCallFixer extends AbstractFixer
  56729. {
  56730. public function getDefinition(): FixerDefinitionInterface
  56731. {
  56732. return new FixerDefinition(
  56733. 'The first argument of `DateTime::createFromFormat` method must start with `!`.',
  56734. [
  56735. new CodeSample("<?php \\DateTime::createFromFormat('Y-m-d', '2022-02-11');\n"),
  56736. ],
  56737. "Consider this code:
  56738. `DateTime::createFromFormat('Y-m-d', '2022-02-11')`.
  56739. What value will be returned? '2022-02-11 00:00:00.0'?
  56740. No, actual return value has 'H:i:s' section like '2022-02-11 16:55:37.0'.
  56741. Change 'Y-m-d' to '!Y-m-d', return value will be '2022-02-11 00:00:00.0'.
  56742. So, adding `!` to format string will make return value more intuitive.",
  56743. 'Risky when depending on the actual timings being used even when not explicit set in format.'
  56744. );
  56745. }
  56746. public function getPriority(): int
  56747. {
  56748. return 0;
  56749. }
  56750. public function isCandidate(Tokens $tokens): bool
  56751. {
  56752. return $tokens->isTokenKindFound(T_DOUBLE_COLON);
  56753. }
  56754. public function isRisky(): bool
  56755. {
  56756. return true;
  56757. }
  56758. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  56759. {
  56760. $argumentsAnalyzer = new ArgumentsAnalyzer();
  56761. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  56762. foreach ($tokens->getNamespaceDeclarations() as $namespace) {
  56763. $scopeStartIndex = $namespace->getScopeStartIndex();
  56764. $useDeclarations = $namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace);
  56765. for ($index = $namespace->getScopeEndIndex(); $index > $scopeStartIndex; --$index) {
  56766. if (!$tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  56767. continue;
  56768. }
  56769. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  56770. if (!$tokens[$functionNameIndex]->equals([T_STRING, 'createFromFormat'], false)) {
  56771. continue;
  56772. }
  56773. if (!$tokens[$tokens->getNextMeaningfulToken($functionNameIndex)]->equals('(')) {
  56774. continue;
  56775. }
  56776. $classNameIndex = $tokens->getPrevMeaningfulToken($index);
  56777. if (!$tokens[$classNameIndex]->equalsAny([[T_STRING, \DateTime::class], [T_STRING, \DateTimeImmutable::class]], false)) {
  56778. continue;
  56779. }
  56780. $preClassNameIndex = $tokens->getPrevMeaningfulToken($classNameIndex);
  56781. if ($tokens[$preClassNameIndex]->isGivenKind(T_NS_SEPARATOR)) {
  56782. if ($tokens[$tokens->getPrevMeaningfulToken($preClassNameIndex)]->isGivenKind(T_STRING)) {
  56783. continue;
  56784. }
  56785. } elseif (!$namespace->isGlobalNamespace()) {
  56786. continue;
  56787. } else {
  56788. foreach ($useDeclarations as $useDeclaration) {
  56789. foreach (['datetime', 'datetimeimmutable'] as $name) {
  56790. if ($name === strtolower($useDeclaration->getShortName()) && $name !== strtolower($useDeclaration->getFullName())) {
  56791. continue 3;
  56792. }
  56793. }
  56794. }
  56795. }
  56796. $openIndex = $tokens->getNextTokenOfKind($functionNameIndex, ['(']);
  56797. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  56798. $argumentIndex = $this->getFirstArgumentTokenIndex($tokens, $argumentsAnalyzer->getArguments($tokens, $openIndex, $closeIndex));
  56799. if (null === $argumentIndex) {
  56800. continue;
  56801. }
  56802. $format = $tokens[$argumentIndex]->getContent();
  56803. if (\strlen($format) < 3) {
  56804. continue;
  56805. }
  56806. $offset = 'b' === $format[0] || 'B' === $format[0] ? 2 : 1;
  56807. if ('!' === $format[$offset]) {
  56808. continue;
  56809. }
  56810. $tokens->clearAt($argumentIndex);
  56811. $tokens->insertAt($argumentIndex, new Token([T_CONSTANT_ENCAPSED_STRING, substr_replace($format, '!', $offset, 0)]));
  56812. }
  56813. }
  56814. }
  56815. private function getFirstArgumentTokenIndex(Tokens $tokens, array $arguments): ?int
  56816. {
  56817. if (2 !== \count($arguments)) {
  56818. return null;
  56819. }
  56820. $argumentStartIndex = array_key_first($arguments);
  56821. $argumentEndIndex = $arguments[$argumentStartIndex];
  56822. $argumentStartIndex = $tokens->getNextMeaningfulToken($argumentStartIndex - 1);
  56823. if (
  56824. $argumentStartIndex !== $argumentEndIndex
  56825. && $tokens->getNextMeaningfulToken($argumentStartIndex) <= $argumentEndIndex
  56826. ) {
  56827. return null;
  56828. }
  56829. return !$tokens[$argumentStartIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)
  56830. ? null
  56831. : $argumentStartIndex;
  56832. }
  56833. }
  56834. <?php
  56835. declare(strict_types=1);
  56836. namespace PhpCsFixer\Fixer\FunctionNotation;
  56837. use PhpCsFixer\AbstractFixer;
  56838. use PhpCsFixer\FixerDefinition\CodeSample;
  56839. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56840. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56841. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  56842. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  56843. use PhpCsFixer\Tokenizer\Tokens;
  56844. final class NoUselessSprintfFixer extends AbstractFixer
  56845. {
  56846. public function getDefinition(): FixerDefinitionInterface
  56847. {
  56848. return new FixerDefinition(
  56849. 'There must be no `sprintf` calls with only the first argument.',
  56850. [
  56851. new CodeSample(
  56852. "<?php\n\$foo = sprintf('bar');\n"
  56853. ),
  56854. ],
  56855. null,
  56856. 'Risky when if the `sprintf` function is overridden.'
  56857. );
  56858. }
  56859. public function isCandidate(Tokens $tokens): bool
  56860. {
  56861. return $tokens->isTokenKindFound(T_STRING);
  56862. }
  56863. public function isRisky(): bool
  56864. {
  56865. return true;
  56866. }
  56867. public function getPriority(): int
  56868. {
  56869. return 42;
  56870. }
  56871. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  56872. {
  56873. $functionAnalyzer = new FunctionsAnalyzer();
  56874. $argumentsAnalyzer = new ArgumentsAnalyzer();
  56875. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  56876. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  56877. continue;
  56878. }
  56879. if ('sprintf' !== strtolower($tokens[$index]->getContent())) {
  56880. continue;
  56881. }
  56882. if (!$functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  56883. continue;
  56884. }
  56885. $openParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(']);
  56886. if ($tokens[$tokens->getNextMeaningfulToken($openParenthesisIndex)]->isGivenKind(T_ELLIPSIS)) {
  56887. continue;
  56888. }
  56889. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  56890. if (1 !== $argumentsAnalyzer->countArguments($tokens, $openParenthesisIndex, $closeParenthesisIndex)) {
  56891. continue;
  56892. }
  56893. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesisIndex);
  56894. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  56895. if ($tokens[$prevMeaningfulTokenIndex]->equals(',')) {
  56896. $tokens->clearTokenAndMergeSurroundingWhitespace($prevMeaningfulTokenIndex);
  56897. }
  56898. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesisIndex);
  56899. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  56900. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($index);
  56901. if ($tokens[$prevMeaningfulTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  56902. $tokens->clearTokenAndMergeSurroundingWhitespace($prevMeaningfulTokenIndex);
  56903. }
  56904. }
  56905. }
  56906. }
  56907. <?php
  56908. declare(strict_types=1);
  56909. namespace PhpCsFixer\Fixer\FunctionNotation;
  56910. use PhpCsFixer\AbstractFopenFlagFixer;
  56911. use PhpCsFixer\FixerDefinition\CodeSample;
  56912. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56913. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56914. use PhpCsFixer\Preg;
  56915. use PhpCsFixer\Tokenizer\Token;
  56916. use PhpCsFixer\Tokenizer\Tokens;
  56917. final class FopenFlagOrderFixer extends AbstractFopenFlagFixer
  56918. {
  56919. public function getDefinition(): FixerDefinitionInterface
  56920. {
  56921. return new FixerDefinition(
  56922. 'Order the flags in `fopen` calls, `b` and `t` must be last.',
  56923. [new CodeSample("<?php\n\$a = fopen(\$foo, 'br+');\n")],
  56924. null,
  56925. 'Risky when the function `fopen` is overridden.'
  56926. );
  56927. }
  56928. protected function fixFopenFlagToken(Tokens $tokens, int $argumentStartIndex, int $argumentEndIndex): void
  56929. {
  56930. $argumentFlagIndex = null;
  56931. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  56932. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  56933. continue;
  56934. }
  56935. if (null !== $argumentFlagIndex) {
  56936. return;
  56937. }
  56938. $argumentFlagIndex = $i;
  56939. }
  56940. if (null === $argumentFlagIndex || !$tokens[$argumentFlagIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  56941. return;
  56942. }
  56943. $content = $tokens[$argumentFlagIndex]->getContent();
  56944. $contentQuote = $content[0];
  56945. if ('b' === $contentQuote || 'B' === $contentQuote) {
  56946. $binPrefix = $contentQuote;
  56947. $contentQuote = $content[1];
  56948. $mode = substr($content, 2, -1);
  56949. } else {
  56950. $binPrefix = '';
  56951. $mode = substr($content, 1, -1);
  56952. }
  56953. $modeLength = \strlen($mode);
  56954. if ($modeLength < 2) {
  56955. return;
  56956. }
  56957. if (false === $this->isValidModeString($mode)) {
  56958. return;
  56959. }
  56960. $split = $this->sortFlags(Preg::split('#([^\+]\+?)#', $mode, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE));
  56961. $newContent = $binPrefix.$contentQuote.implode('', $split).$contentQuote;
  56962. if ($content !== $newContent) {
  56963. $tokens[$argumentFlagIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, $newContent]);
  56964. }
  56965. }
  56966. private function sortFlags(array $flags): array
  56967. {
  56968. usort(
  56969. $flags,
  56970. static function (string $flag1, string $flag2): int {
  56971. if ($flag1 === $flag2) {
  56972. return 0;
  56973. }
  56974. if ('b' === $flag1) {
  56975. return 1;
  56976. }
  56977. if ('b' === $flag2) {
  56978. return -1;
  56979. }
  56980. if ('t' === $flag1) {
  56981. return 1;
  56982. }
  56983. if ('t' === $flag2) {
  56984. return -1;
  56985. }
  56986. return $flag1 < $flag2 ? -1 : 1;
  56987. }
  56988. );
  56989. return $flags;
  56990. }
  56991. }
  56992. <?php
  56993. declare(strict_types=1);
  56994. namespace PhpCsFixer\Fixer\FunctionNotation;
  56995. use PhpCsFixer\AbstractFixer;
  56996. use PhpCsFixer\FixerDefinition\CodeSample;
  56997. use PhpCsFixer\FixerDefinition\FixerDefinition;
  56998. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  56999. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  57000. use PhpCsFixer\Tokenizer\Token;
  57001. use PhpCsFixer\Tokenizer\Tokens;
  57002. final class CombineNestedDirnameFixer extends AbstractFixer
  57003. {
  57004. public function getDefinition(): FixerDefinitionInterface
  57005. {
  57006. return new FixerDefinition(
  57007. 'Replace multiple nested calls of `dirname` by only one call with second `$level` parameter.',
  57008. [
  57009. new CodeSample(
  57010. "<?php\ndirname(dirname(dirname(\$path)));\n"
  57011. ),
  57012. ],
  57013. null,
  57014. 'Risky when the function `dirname` is overridden.'
  57015. );
  57016. }
  57017. public function isCandidate(Tokens $tokens): bool
  57018. {
  57019. return $tokens->isTokenKindFound(T_STRING);
  57020. }
  57021. public function isRisky(): bool
  57022. {
  57023. return true;
  57024. }
  57025. public function getPriority(): int
  57026. {
  57027. return 35;
  57028. }
  57029. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  57030. {
  57031. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  57032. $dirnameInfo = $this->getDirnameInfo($tokens, $index);
  57033. if (false === $dirnameInfo) {
  57034. continue;
  57035. }
  57036. $prev = $tokens->getPrevMeaningfulToken($dirnameInfo['indices'][0]);
  57037. if (!$tokens[$prev]->equals('(')) {
  57038. continue;
  57039. }
  57040. $prev = $tokens->getPrevMeaningfulToken($prev);
  57041. $firstArgumentEnd = $dirnameInfo['end'];
  57042. $dirnameInfoArray = [$dirnameInfo];
  57043. while (($dirnameInfo = $this->getDirnameInfo($tokens, $prev, $firstArgumentEnd)) !== false) {
  57044. $dirnameInfoArray[] = $dirnameInfo;
  57045. $prev = $tokens->getPrevMeaningfulToken($dirnameInfo['indices'][0]);
  57046. if (!$tokens[$prev]->equals('(')) {
  57047. break;
  57048. }
  57049. $prev = $tokens->getPrevMeaningfulToken($prev);
  57050. $firstArgumentEnd = $dirnameInfo['end'];
  57051. }
  57052. if (\count($dirnameInfoArray) > 1) {
  57053. $this->combineDirnames($tokens, $dirnameInfoArray);
  57054. }
  57055. $index = $prev;
  57056. }
  57057. }
  57058. private function getDirnameInfo(Tokens $tokens, int $index, ?int $firstArgumentEndIndex = null)
  57059. {
  57060. if (!$tokens[$index]->equals([T_STRING, 'dirname'], false)) {
  57061. return false;
  57062. }
  57063. if (!(new FunctionsAnalyzer())->isGlobalFunctionCall($tokens, $index)) {
  57064. return false;
  57065. }
  57066. $info = ['indices' => []];
  57067. $prev = $tokens->getPrevMeaningfulToken($index);
  57068. if ($tokens[$prev]->isGivenKind(T_NS_SEPARATOR)) {
  57069. $info['indices'][] = $prev;
  57070. }
  57071. $info['indices'][] = $index;
  57072. $next = $tokens->getNextMeaningfulToken($index);
  57073. $info['indices'][] = $next;
  57074. if (null !== $firstArgumentEndIndex) {
  57075. $next = $tokens->getNextMeaningfulToken($firstArgumentEndIndex);
  57076. } else {
  57077. $next = $tokens->getNextMeaningfulToken($next);
  57078. if ($tokens[$next]->equals(')')) {
  57079. return false;
  57080. }
  57081. while (!$tokens[$next]->equalsAny([',', ')'])) {
  57082. $blockType = Tokens::detectBlockType($tokens[$next]);
  57083. if (null !== $blockType) {
  57084. $next = $tokens->findBlockEnd($blockType['type'], $next);
  57085. }
  57086. $next = $tokens->getNextMeaningfulToken($next);
  57087. }
  57088. }
  57089. $info['indices'][] = $next;
  57090. if ($tokens[$next]->equals(',')) {
  57091. $next = $tokens->getNextMeaningfulToken($next);
  57092. $info['indices'][] = $next;
  57093. }
  57094. if ($tokens[$next]->equals(')')) {
  57095. $info['levels'] = 1;
  57096. $info['end'] = $next;
  57097. return $info;
  57098. }
  57099. if (!$tokens[$next]->isGivenKind(T_LNUMBER)) {
  57100. return false;
  57101. }
  57102. $info['secondArgument'] = $next;
  57103. $info['levels'] = (int) $tokens[$next]->getContent();
  57104. $next = $tokens->getNextMeaningfulToken($next);
  57105. if ($tokens[$next]->equals(',')) {
  57106. $info['indices'][] = $next;
  57107. $next = $tokens->getNextMeaningfulToken($next);
  57108. }
  57109. if (!$tokens[$next]->equals(')')) {
  57110. return false;
  57111. }
  57112. $info['indices'][] = $next;
  57113. $info['end'] = $next;
  57114. return $info;
  57115. }
  57116. private function combineDirnames(Tokens $tokens, array $dirnameInfoArray): void
  57117. {
  57118. $outerDirnameInfo = array_pop($dirnameInfoArray);
  57119. $levels = $outerDirnameInfo['levels'];
  57120. foreach ($dirnameInfoArray as $dirnameInfo) {
  57121. $levels += $dirnameInfo['levels'];
  57122. foreach ($dirnameInfo['indices'] as $index) {
  57123. $tokens->removeLeadingWhitespace($index);
  57124. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  57125. }
  57126. }
  57127. $levelsToken = new Token([T_LNUMBER, (string) $levels]);
  57128. if (isset($outerDirnameInfo['secondArgument'])) {
  57129. $tokens[$outerDirnameInfo['secondArgument']] = $levelsToken;
  57130. } else {
  57131. $prev = $tokens->getPrevMeaningfulToken($outerDirnameInfo['end']);
  57132. $items = [];
  57133. if (!$tokens[$prev]->equals(',')) {
  57134. $items = [new Token(','), new Token([T_WHITESPACE, ' '])];
  57135. }
  57136. $items[] = $levelsToken;
  57137. $tokens->insertAt($outerDirnameInfo['end'], $items);
  57138. }
  57139. }
  57140. }
  57141. <?php
  57142. declare(strict_types=1);
  57143. namespace PhpCsFixer\Fixer\FunctionNotation;
  57144. use PhpCsFixer\AbstractFixer;
  57145. use PhpCsFixer\FixerDefinition\CodeSample;
  57146. use PhpCsFixer\FixerDefinition\FixerDefinition;
  57147. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  57148. use PhpCsFixer\Tokenizer\CT;
  57149. use PhpCsFixer\Tokenizer\Tokens;
  57150. final class NoSpacesAfterFunctionNameFixer extends AbstractFixer
  57151. {
  57152. public function getDefinition(): FixerDefinitionInterface
  57153. {
  57154. return new FixerDefinition(
  57155. 'When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis.',
  57156. [new CodeSample("<?php\nstrlen ('Hello World!');\nfoo (test (3));\nexit (1);\n\$func ();\n")]
  57157. );
  57158. }
  57159. public function getPriority(): int
  57160. {
  57161. return 3;
  57162. }
  57163. public function isCandidate(Tokens $tokens): bool
  57164. {
  57165. return $tokens->isAnyTokenKindsFound([T_STRING, ...$this->getFunctionyTokenKinds()]);
  57166. }
  57167. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  57168. {
  57169. $functionyTokens = $this->getFunctionyTokenKinds();
  57170. $languageConstructionTokens = $this->getLanguageConstructionTokenKinds();
  57171. $braceTypes = $this->getBraceAfterVariableKinds();
  57172. foreach ($tokens as $index => $token) {
  57173. if (!$token->equals('(')) {
  57174. continue;
  57175. }
  57176. $lastTokenIndex = $tokens->getPrevNonWhitespace($index);
  57177. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  57178. $nextNonWhiteSpace = $tokens->getNextMeaningfulToken($endParenthesisIndex);
  57179. if (
  57180. null !== $nextNonWhiteSpace
  57181. && !$tokens[$nextNonWhiteSpace]->equals(';')
  57182. && $tokens[$lastTokenIndex]->isGivenKind($languageConstructionTokens)
  57183. ) {
  57184. continue;
  57185. }
  57186. if ($tokens[$lastTokenIndex]->isGivenKind($functionyTokens)) {
  57187. $this->fixFunctionCall($tokens, $index);
  57188. } elseif ($tokens[$lastTokenIndex]->isGivenKind(T_STRING)) {
  57189. $possibleDefinitionIndex = $tokens->getPrevMeaningfulToken($lastTokenIndex);
  57190. if (!$tokens[$possibleDefinitionIndex]->isGivenKind(T_FUNCTION)) {
  57191. $this->fixFunctionCall($tokens, $index);
  57192. }
  57193. } elseif ($tokens[$lastTokenIndex]->equalsAny($braceTypes)) {
  57194. $block = Tokens::detectBlockType($tokens[$lastTokenIndex]);
  57195. if (
  57196. Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE === $block['type']
  57197. || Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE === $block['type']
  57198. || Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE === $block['type']
  57199. || Tokens::BLOCK_TYPE_PARENTHESIS_BRACE === $block['type']
  57200. ) {
  57201. $this->fixFunctionCall($tokens, $index);
  57202. }
  57203. }
  57204. }
  57205. }
  57206. private function fixFunctionCall(Tokens $tokens, int $index): void
  57207. {
  57208. if ($tokens[$index - 1]->isWhitespace()) {
  57209. $tokens->clearAt($index - 1);
  57210. }
  57211. }
  57212. private function getBraceAfterVariableKinds(): array
  57213. {
  57214. return [
  57215. ')',
  57216. ']',
  57217. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  57218. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  57219. ];
  57220. }
  57221. private function getFunctionyTokenKinds(): array
  57222. {
  57223. static $tokens = [
  57224. T_ARRAY,
  57225. T_ECHO,
  57226. T_EMPTY,
  57227. T_EVAL,
  57228. T_EXIT,
  57229. T_INCLUDE,
  57230. T_INCLUDE_ONCE,
  57231. T_ISSET,
  57232. T_LIST,
  57233. T_PRINT,
  57234. T_REQUIRE,
  57235. T_REQUIRE_ONCE,
  57236. T_UNSET,
  57237. T_VARIABLE,
  57238. ];
  57239. return $tokens;
  57240. }
  57241. private function getLanguageConstructionTokenKinds(): array
  57242. {
  57243. static $languageConstructionTokens = [
  57244. T_ECHO,
  57245. T_PRINT,
  57246. T_INCLUDE,
  57247. T_INCLUDE_ONCE,
  57248. T_REQUIRE,
  57249. T_REQUIRE_ONCE,
  57250. ];
  57251. return $languageConstructionTokens;
  57252. }
  57253. }
  57254. <?php
  57255. declare(strict_types=1);
  57256. namespace PhpCsFixer\Fixer\FunctionNotation;
  57257. use PhpCsFixer\AbstractPhpdocToTypeDeclarationFixer;
  57258. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  57259. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  57260. use PhpCsFixer\FixerDefinition\CodeSample;
  57261. use PhpCsFixer\FixerDefinition\FixerDefinition;
  57262. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  57263. use PhpCsFixer\FixerDefinition\VersionSpecification;
  57264. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  57265. use PhpCsFixer\Tokenizer\CT;
  57266. use PhpCsFixer\Tokenizer\Token;
  57267. use PhpCsFixer\Tokenizer\Tokens;
  57268. /**
  57269. @phpstan-type
  57270. @phpstan-type
  57271. @implements
  57272. */
  57273. final class PhpdocToReturnTypeFixer extends AbstractPhpdocToTypeDeclarationFixer implements ConfigurableFixerInterface, ExperimentalFixerInterface
  57274. {
  57275. private const TYPE_CHECK_TEMPLATE = '<?php function f(): %s {}';
  57276. private array $excludeFuncNames = [
  57277. [T_STRING, '__construct'],
  57278. [T_STRING, '__destruct'],
  57279. [T_STRING, '__clone'],
  57280. ];
  57281. private array $skippedTypes = [
  57282. 'resource' => true,
  57283. 'null' => true,
  57284. ];
  57285. public function getDefinition(): FixerDefinitionInterface
  57286. {
  57287. return new FixerDefinition(
  57288. 'Takes `@return` annotation of non-mixed types and adjusts accordingly the function signature.',
  57289. [
  57290. new CodeSample(
  57291. '<?php
  57292. /** @return \My\Bar */
  57293. function f1()
  57294. {}
  57295. /** @return void */
  57296. function f2()
  57297. {}
  57298. /** @return object */
  57299. function my_foo()
  57300. {}
  57301. ',
  57302. ),
  57303. new CodeSample(
  57304. '<?php
  57305. /** @return Foo */
  57306. function foo() {}
  57307. /** @return string */
  57308. function bar() {}
  57309. ',
  57310. ['scalar_types' => false]
  57311. ),
  57312. new CodeSample(
  57313. '<?php
  57314. /** @return Foo */
  57315. function foo() {}
  57316. /** @return int|string */
  57317. function bar() {}
  57318. ',
  57319. ['union_types' => false]
  57320. ),
  57321. new VersionSpecificCodeSample(
  57322. '<?php
  57323. final class Foo {
  57324. /**
  57325. * @return static
  57326. */
  57327. public function create($prototype) {
  57328. return new static($prototype);
  57329. }
  57330. }
  57331. ',
  57332. new VersionSpecification(8_00_00)
  57333. ),
  57334. ],
  57335. null,
  57336. 'The `@return` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. Manual actions are required if inherited signatures are not properly documented.'
  57337. );
  57338. }
  57339. public function isCandidate(Tokens $tokens): bool
  57340. {
  57341. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  57342. }
  57343. public function getPriority(): int
  57344. {
  57345. return 13;
  57346. }
  57347. protected function isSkippedType(string $type): bool
  57348. {
  57349. return isset($this->skippedTypes[$type]);
  57350. }
  57351. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  57352. {
  57353. for ($index = $tokens->count() - 1; 0 < $index; --$index) {
  57354. if (!$tokens[$index]->isGivenKind([T_FUNCTION, T_FN])) {
  57355. continue;
  57356. }
  57357. $funcName = $tokens->getNextMeaningfulToken($index);
  57358. if ($tokens[$funcName]->equalsAny($this->excludeFuncNames, false)) {
  57359. continue;
  57360. }
  57361. $docCommentIndex = $this->findFunctionDocComment($tokens, $index);
  57362. if (null === $docCommentIndex) {
  57363. continue;
  57364. }
  57365. $returnTypeAnnotations = $this->getAnnotationsFromDocComment('return', $tokens, $docCommentIndex);
  57366. if (1 !== \count($returnTypeAnnotations)) {
  57367. continue;
  57368. }
  57369. $returnTypeAnnotation = $returnTypeAnnotations[0];
  57370. $typesExpression = $returnTypeAnnotation->getTypeExpression();
  57371. if (null === $typesExpression) {
  57372. continue;
  57373. }
  57374. $typeInfo = $this->getCommonTypeInfo($typesExpression, true);
  57375. $unionTypes = null;
  57376. if (null === $typeInfo) {
  57377. $unionTypes = $this->getUnionTypes($typesExpression, true);
  57378. }
  57379. if (null === $typeInfo && null === $unionTypes) {
  57380. continue;
  57381. }
  57382. if (null !== $typeInfo) {
  57383. $returnType = $typeInfo['commonType'];
  57384. $isNullable = $typeInfo['isNullable'];
  57385. } elseif (null !== $unionTypes) {
  57386. $returnType = $unionTypes;
  57387. $isNullable = false;
  57388. }
  57389. if (!isset($returnType, $isNullable)) {
  57390. continue;
  57391. }
  57392. $paramsStartIndex = $tokens->getNextTokenOfKind($index, ['(']);
  57393. $paramsEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $paramsStartIndex);
  57394. $bodyStartIndex = $tokens->getNextTokenOfKind($paramsEndIndex, ['{', ';', [T_DOUBLE_ARROW]]);
  57395. if ($this->hasReturnTypeHint($tokens, $bodyStartIndex)) {
  57396. continue;
  57397. }
  57398. if (!$this->isValidSyntax(\sprintf(self::TYPE_CHECK_TEMPLATE, $returnType))) {
  57399. continue;
  57400. }
  57401. $tokens->insertAt(
  57402. $paramsEndIndex + 1,
  57403. array_merge(
  57404. [
  57405. new Token([CT::T_TYPE_COLON, ':']),
  57406. new Token([T_WHITESPACE, ' ']),
  57407. ],
  57408. $this->createTypeDeclarationTokens($returnType, $isNullable)
  57409. )
  57410. );
  57411. }
  57412. }
  57413. protected function createTokensFromRawType(string $type): Tokens
  57414. {
  57415. $typeTokens = Tokens::fromCode(\sprintf(self::TYPE_CHECK_TEMPLATE, $type));
  57416. $typeTokens->clearRange(0, 7);
  57417. $typeTokens->clearRange(\count($typeTokens) - 3, \count($typeTokens) - 1);
  57418. $typeTokens->clearEmptyTokens();
  57419. return $typeTokens;
  57420. }
  57421. private function hasReturnTypeHint(Tokens $tokens, int $index): bool
  57422. {
  57423. $endFuncIndex = $tokens->getPrevTokenOfKind($index, [')']);
  57424. $nextIndex = $tokens->getNextMeaningfulToken($endFuncIndex);
  57425. return $tokens[$nextIndex]->isGivenKind(CT::T_TYPE_COLON);
  57426. }
  57427. }
  57428. <?php
  57429. declare(strict_types=1);
  57430. namespace PhpCsFixer\Fixer\FunctionNotation;
  57431. use PhpCsFixer\AbstractFixer;
  57432. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  57433. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  57434. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  57435. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  57436. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  57437. use PhpCsFixer\FixerDefinition\CodeSample;
  57438. use PhpCsFixer\FixerDefinition\FixerDefinition;
  57439. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  57440. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  57441. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  57442. use PhpCsFixer\Tokenizer\Token;
  57443. use PhpCsFixer\Tokenizer\Tokens;
  57444. use PhpCsFixer\Utils;
  57445. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  57446. /**
  57447. @phpstan-type
  57448. @phpstan-type
  57449. @implements
  57450. */
  57451. final class NativeFunctionInvocationFixer extends AbstractFixer implements ConfigurableFixerInterface
  57452. {
  57453. /**
  57454. @use */
  57455. use ConfigurableFixerTrait;
  57456. public const SET_ALL = '@all';
  57457. public const SET_COMPILER_OPTIMIZED = '@compiler_optimized';
  57458. public const SET_INTERNAL = '@internal';
  57459. private $functionFilter;
  57460. public function getDefinition(): FixerDefinitionInterface
  57461. {
  57462. return new FixerDefinition(
  57463. 'Add leading `\` before function invocation to speed up resolving.',
  57464. [
  57465. new CodeSample(
  57466. '<?php
  57467. function baz($options)
  57468. {
  57469. if (!array_key_exists("foo", $options)) {
  57470. throw new \InvalidArgumentException();
  57471. }
  57472. return json_encode($options);
  57473. }
  57474. '
  57475. ),
  57476. new CodeSample(
  57477. '<?php
  57478. function baz($options)
  57479. {
  57480. if (!array_key_exists("foo", $options)) {
  57481. throw new \InvalidArgumentException();
  57482. }
  57483. return json_encode($options);
  57484. }
  57485. ',
  57486. [
  57487. 'exclude' => [
  57488. 'json_encode',
  57489. ],
  57490. ]
  57491. ),
  57492. new CodeSample(
  57493. '<?php
  57494. namespace space1 {
  57495. echo count([1]);
  57496. }
  57497. namespace {
  57498. echo count([1]);
  57499. }
  57500. ',
  57501. ['scope' => 'all']
  57502. ),
  57503. new CodeSample(
  57504. '<?php
  57505. namespace space1 {
  57506. echo count([1]);
  57507. }
  57508. namespace {
  57509. echo count([1]);
  57510. }
  57511. ',
  57512. ['scope' => 'namespaced']
  57513. ),
  57514. new CodeSample(
  57515. '<?php
  57516. myGlobalFunction();
  57517. count();
  57518. ',
  57519. ['include' => ['myGlobalFunction']]
  57520. ),
  57521. new CodeSample(
  57522. '<?php
  57523. myGlobalFunction();
  57524. count();
  57525. ',
  57526. ['include' => [self::SET_ALL]]
  57527. ),
  57528. new CodeSample(
  57529. '<?php
  57530. myGlobalFunction();
  57531. count();
  57532. ',
  57533. ['include' => [self::SET_INTERNAL]]
  57534. ),
  57535. new CodeSample(
  57536. '<?php
  57537. $a .= str_repeat($a, 4);
  57538. $c = get_class($d);
  57539. ',
  57540. ['include' => [self::SET_COMPILER_OPTIMIZED]]
  57541. ),
  57542. ],
  57543. null,
  57544. 'Risky when any of the functions are overridden.'
  57545. );
  57546. }
  57547. public function getPriority(): int
  57548. {
  57549. return 1;
  57550. }
  57551. public function isCandidate(Tokens $tokens): bool
  57552. {
  57553. return $tokens->isTokenKindFound(T_STRING);
  57554. }
  57555. public function isRisky(): bool
  57556. {
  57557. return true;
  57558. }
  57559. protected function configurePostNormalisation(): void
  57560. {
  57561. $this->functionFilter = $this->getFunctionFilter();
  57562. }
  57563. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  57564. {
  57565. if ('all' === $this->configuration['scope']) {
  57566. $this->fixFunctionCalls($tokens, $this->functionFilter, 0, \count($tokens) - 1, false);
  57567. return;
  57568. }
  57569. $namespaces = $tokens->getNamespaceDeclarations();
  57570. foreach (array_reverse($namespaces) as $namespace) {
  57571. $this->fixFunctionCalls($tokens, $this->functionFilter, $namespace->getScopeStartIndex(), $namespace->getScopeEndIndex(), $namespace->isGlobalNamespace());
  57572. }
  57573. }
  57574. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  57575. {
  57576. return new FixerConfigurationResolver([
  57577. (new FixerOptionBuilder('exclude', 'List of functions to ignore.'))
  57578. ->setAllowedTypes(['string[]'])
  57579. ->setAllowedValues([static function (array $value): bool {
  57580. foreach ($value as $functionName) {
  57581. if ('' === trim($functionName) || trim($functionName) !== $functionName) {
  57582. throw new InvalidOptionsException(\sprintf(
  57583. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  57584. get_debug_type($functionName)
  57585. ));
  57586. }
  57587. }
  57588. return true;
  57589. }])
  57590. ->setDefault([])
  57591. ->getOption(),
  57592. (new FixerOptionBuilder('include', 'List of function names or sets to fix. Defined sets are `@internal` (all native functions), `@all` (all global functions) and `@compiler_optimized` (functions that are specially optimized by Zend).'))
  57593. ->setAllowedTypes(['string[]'])
  57594. ->setAllowedValues([static function (array $value): bool {
  57595. foreach ($value as $functionName) {
  57596. if ('' === trim($functionName) || trim($functionName) !== $functionName) {
  57597. throw new InvalidOptionsException(\sprintf(
  57598. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  57599. get_debug_type($functionName)
  57600. ));
  57601. }
  57602. $sets = [
  57603. self::SET_ALL,
  57604. self::SET_INTERNAL,
  57605. self::SET_COMPILER_OPTIMIZED,
  57606. ];
  57607. if (str_starts_with($functionName, '@') && !\in_array($functionName, $sets, true)) {
  57608. throw new InvalidOptionsException(\sprintf('Unknown set "%s", known sets are %s.', $functionName, Utils::naturalLanguageJoin($sets)));
  57609. }
  57610. }
  57611. return true;
  57612. }])
  57613. ->setDefault([self::SET_COMPILER_OPTIMIZED])
  57614. ->getOption(),
  57615. (new FixerOptionBuilder('scope', 'Only fix function calls that are made within a namespace or fix all.'))
  57616. ->setAllowedValues(['all', 'namespaced'])
  57617. ->setDefault('all')
  57618. ->getOption(),
  57619. (new FixerOptionBuilder('strict', 'Whether leading `\` of function call not meant to have it should be removed.'))
  57620. ->setAllowedTypes(['bool'])
  57621. ->setDefault(true)
  57622. ->getOption(),
  57623. ]);
  57624. }
  57625. private function fixFunctionCalls(Tokens $tokens, callable $functionFilter, int $start, int $end, bool $tryToRemove): void
  57626. {
  57627. $functionsAnalyzer = new FunctionsAnalyzer();
  57628. $tokensToInsert = [];
  57629. for ($index = $start; $index < $end; ++$index) {
  57630. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  57631. continue;
  57632. }
  57633. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  57634. if (!$functionFilter($tokens[$index]->getContent()) || $tryToRemove) {
  57635. if (false === $this->configuration['strict']) {
  57636. continue;
  57637. }
  57638. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  57639. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  57640. }
  57641. continue;
  57642. }
  57643. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  57644. continue;
  57645. }
  57646. $tokensToInsert[$index] = new Token([T_NS_SEPARATOR, '\\']);
  57647. }
  57648. $tokens->insertSlices($tokensToInsert);
  57649. }
  57650. private function getFunctionFilter(): callable
  57651. {
  57652. $exclude = $this->normalizeFunctionNames($this->configuration['exclude']);
  57653. if (\in_array(self::SET_ALL, $this->configuration['include'], true)) {
  57654. if (\count($exclude) > 0) {
  57655. return static fn (string $functionName): bool => !isset($exclude[strtolower($functionName)]);
  57656. }
  57657. return static fn (): bool => true;
  57658. }
  57659. $include = [];
  57660. if (\in_array(self::SET_INTERNAL, $this->configuration['include'], true)) {
  57661. $include = $this->getAllInternalFunctionsNormalized();
  57662. } elseif (\in_array(self::SET_COMPILER_OPTIMIZED, $this->configuration['include'], true)) {
  57663. $include = $this->getAllCompilerOptimizedFunctionsNormalized();
  57664. }
  57665. foreach ($this->configuration['include'] as $additional) {
  57666. if (!str_starts_with($additional, '@')) {
  57667. $include[strtolower($additional)] = true;
  57668. }
  57669. }
  57670. if (\count($exclude) > 0) {
  57671. return static fn (string $functionName): bool => isset($include[strtolower($functionName)]) && !isset($exclude[strtolower($functionName)]);
  57672. }
  57673. return static fn (string $functionName): bool => isset($include[strtolower($functionName)]);
  57674. }
  57675. private function getAllCompilerOptimizedFunctionsNormalized(): array
  57676. {
  57677. return $this->normalizeFunctionNames([
  57678. 'array_key_exists',
  57679. 'array_slice',
  57680. 'assert',
  57681. 'boolval',
  57682. 'call_user_func',
  57683. 'call_user_func_array',
  57684. 'chr',
  57685. 'count',
  57686. 'defined',
  57687. 'doubleval',
  57688. 'floatval',
  57689. 'func_get_args',
  57690. 'func_num_args',
  57691. 'get_called_class',
  57692. 'get_class',
  57693. 'gettype',
  57694. 'in_array',
  57695. 'intval',
  57696. 'is_array',
  57697. 'is_bool',
  57698. 'is_double',
  57699. 'is_float',
  57700. 'is_int',
  57701. 'is_integer',
  57702. 'is_long',
  57703. 'is_null',
  57704. 'is_object',
  57705. 'is_real',
  57706. 'is_resource',
  57707. 'is_scalar',
  57708. 'is_string',
  57709. 'ord',
  57710. 'sizeof',
  57711. 'sprintf',
  57712. 'strlen',
  57713. 'strval',
  57714. 'constant',
  57715. 'define',
  57716. 'dirname',
  57717. 'extension_loaded',
  57718. 'function_exists',
  57719. 'is_callable',
  57720. 'ini_get',
  57721. ]);
  57722. }
  57723. private function getAllInternalFunctionsNormalized(): array
  57724. {
  57725. return $this->normalizeFunctionNames(get_defined_functions()['internal']);
  57726. }
  57727. private function normalizeFunctionNames(array $functionNames): array
  57728. {
  57729. $result = [];
  57730. foreach ($functionNames as $functionName) {
  57731. $result[strtolower($functionName)] = true;
  57732. }
  57733. return $result;
  57734. }
  57735. }
  57736. <?php
  57737. declare(strict_types=1);
  57738. namespace PhpCsFixer\Fixer\FunctionNotation;
  57739. use PhpCsFixer\AbstractFopenFlagFixer;
  57740. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  57741. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  57742. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  57743. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  57744. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  57745. use PhpCsFixer\FixerDefinition\CodeSample;
  57746. use PhpCsFixer\FixerDefinition\FixerDefinition;
  57747. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  57748. use PhpCsFixer\Tokenizer\Token;
  57749. use PhpCsFixer\Tokenizer\Tokens;
  57750. /**
  57751. @phpstan-type
  57752. @phpstan-type
  57753. @implements
  57754. */
  57755. final class FopenFlagsFixer extends AbstractFopenFlagFixer implements ConfigurableFixerInterface
  57756. {
  57757. /**
  57758. @use */
  57759. use ConfigurableFixerTrait;
  57760. public function getDefinition(): FixerDefinitionInterface
  57761. {
  57762. return new FixerDefinition(
  57763. 'The flags in `fopen` calls must omit `t`, and `b` must be omitted or included consistently.',
  57764. [
  57765. new CodeSample("<?php\n\$a = fopen(\$foo, 'rwt');\n"),
  57766. new CodeSample("<?php\n\$a = fopen(\$foo, 'rwt');\n", ['b_mode' => false]),
  57767. ],
  57768. null,
  57769. 'Risky when the function `fopen` is overridden.'
  57770. );
  57771. }
  57772. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  57773. {
  57774. return new FixerConfigurationResolver([
  57775. (new FixerOptionBuilder('b_mode', 'The `b` flag must be used (`true`) or omitted (`false`).'))
  57776. ->setAllowedTypes(['bool'])
  57777. ->setDefault(true)
  57778. ->getOption(),
  57779. ]);
  57780. }
  57781. protected function fixFopenFlagToken(Tokens $tokens, int $argumentStartIndex, int $argumentEndIndex): void
  57782. {
  57783. $argumentFlagIndex = null;
  57784. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  57785. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  57786. continue;
  57787. }
  57788. if (null !== $argumentFlagIndex) {
  57789. return;
  57790. }
  57791. $argumentFlagIndex = $i;
  57792. }
  57793. if (null === $argumentFlagIndex || !$tokens[$argumentFlagIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  57794. return;
  57795. }
  57796. $content = $tokens[$argumentFlagIndex]->getContent();
  57797. $contentQuote = $content[0];
  57798. if ('b' === $contentQuote || 'B' === $contentQuote) {
  57799. $binPrefix = $contentQuote;
  57800. $contentQuote = $content[1];
  57801. $mode = substr($content, 2, -1);
  57802. } else {
  57803. $binPrefix = '';
  57804. $mode = substr($content, 1, -1);
  57805. }
  57806. if (false === $this->isValidModeString($mode)) {
  57807. return;
  57808. }
  57809. $mode = str_replace('t', '', $mode);
  57810. if (true === $this->configuration['b_mode']) {
  57811. if (!str_contains($mode, 'b')) {
  57812. $mode .= 'b';
  57813. }
  57814. } else {
  57815. $mode = str_replace('b', '', $mode);
  57816. }
  57817. $newContent = $binPrefix.$contentQuote.$mode.$contentQuote;
  57818. if ($content !== $newContent) {
  57819. $tokens[$argumentFlagIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, $newContent]);
  57820. }
  57821. }
  57822. }
  57823. <?php
  57824. declare(strict_types=1);
  57825. namespace PhpCsFixer\Fixer\FunctionNotation;
  57826. use PhpCsFixer\AbstractFixer;
  57827. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  57828. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  57829. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  57830. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  57831. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  57832. use PhpCsFixer\FixerDefinition\CodeSample;
  57833. use PhpCsFixer\FixerDefinition\FixerDefinition;
  57834. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  57835. use PhpCsFixer\FixerDefinition\VersionSpecification;
  57836. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  57837. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  57838. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  57839. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  57840. use PhpCsFixer\Tokenizer\CT;
  57841. use PhpCsFixer\Tokenizer\FCT;
  57842. use PhpCsFixer\Tokenizer\Token;
  57843. use PhpCsFixer\Tokenizer\Tokens;
  57844. /**
  57845. @phpstan-type
  57846. @phpstan-type
  57847. @implements
  57848. */
  57849. final class NullableTypeDeclarationForDefaultNullValueFixer extends AbstractFixer implements ConfigurableFixerInterface
  57850. {
  57851. /**
  57852. @use */
  57853. use ConfigurableFixerTrait;
  57854. private const CONSTRUCTOR_PROPERTY_MODIFIERS = [
  57855. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  57856. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  57857. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  57858. FCT::T_PUBLIC_SET,
  57859. FCT::T_PROTECTED_SET,
  57860. FCT::T_PRIVATE_SET,
  57861. FCT::T_READONLY,
  57862. ];
  57863. public function getDefinition(): FixerDefinitionInterface
  57864. {
  57865. return new FixerDefinition(
  57866. 'Adds or removes `?` before single type declarations or `|null` at the end of union types when parameters have a default `null` value.',
  57867. [
  57868. new CodeSample(
  57869. "<?php\nfunction sample(string \$str = null)\n{}\n"
  57870. ),
  57871. new CodeSample(
  57872. "<?php\nfunction sample(?string \$str = null)\n{}\n",
  57873. ['use_nullable_type_declaration' => false]
  57874. ),
  57875. new VersionSpecificCodeSample(
  57876. "<?php\nfunction sample(string|int \$str = null)\n{}\n",
  57877. new VersionSpecification(8_00_00)
  57878. ),
  57879. new VersionSpecificCodeSample(
  57880. "<?php\nfunction sample(string|int|null \$str = null)\n{}\n",
  57881. new VersionSpecification(8_00_00),
  57882. ['use_nullable_type_declaration' => false]
  57883. ),
  57884. new VersionSpecificCodeSample(
  57885. "<?php\nfunction sample(\\Foo&\\Bar \$str = null)\n{}\n",
  57886. new VersionSpecification(8_02_00)
  57887. ),
  57888. new VersionSpecificCodeSample(
  57889. "<?php\nfunction sample((\\Foo&\\Bar)|null \$str = null)\n{}\n",
  57890. new VersionSpecification(8_02_00),
  57891. ['use_nullable_type_declaration' => false]
  57892. ),
  57893. ],
  57894. 'Rule is applied only in a PHP 7.1+ environment.'
  57895. );
  57896. }
  57897. public function isCandidate(Tokens $tokens): bool
  57898. {
  57899. return $tokens->isTokenKindFound(T_VARIABLE) && $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  57900. }
  57901. public function getPriority(): int
  57902. {
  57903. return 3;
  57904. }
  57905. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  57906. {
  57907. return new FixerConfigurationResolver([
  57908. (new FixerOptionBuilder('use_nullable_type_declaration', 'Whether to add or remove `?` or `|null` to parameters with a default `null` value.'))
  57909. ->setAllowedTypes(['bool'])
  57910. ->setDefault(true)
  57911. ->setDeprecationMessage('Behaviour will follow default one.')
  57912. ->getOption(),
  57913. ]);
  57914. }
  57915. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  57916. {
  57917. $functionsAnalyzer = new FunctionsAnalyzer();
  57918. $tokenKinds = [T_FUNCTION, T_FN];
  57919. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  57920. $token = $tokens[$index];
  57921. if (!$token->isGivenKind($tokenKinds)) {
  57922. continue;
  57923. }
  57924. $arguments = $functionsAnalyzer->getFunctionArguments($tokens, $index);
  57925. $this->fixFunctionParameters($tokens, $arguments);
  57926. }
  57927. }
  57928. private function fixFunctionParameters(Tokens $tokens, array $arguments): void
  57929. {
  57930. foreach (array_reverse($arguments) as $argumentInfo) {
  57931. if (
  57932. !$argumentInfo->hasTypeAnalysis()
  57933. || \in_array(strtolower($argumentInfo->getTypeAnalysis()->getName()), ['mixed', 'null'], true)
  57934. || !$argumentInfo->hasDefault() || 'null' !== strtolower($argumentInfo->getDefault())
  57935. ) {
  57936. continue;
  57937. }
  57938. $argumentTypeInfo = $argumentInfo->getTypeAnalysis();
  57939. if (\PHP_VERSION_ID >= 8_00_00 && false === $this->configuration['use_nullable_type_declaration']) {
  57940. $visibility = $tokens[$tokens->getPrevMeaningfulToken($argumentTypeInfo->getStartIndex())];
  57941. if ($visibility->isGivenKind(self::CONSTRUCTOR_PROPERTY_MODIFIERS)) {
  57942. continue;
  57943. }
  57944. }
  57945. $typeAnalysisName = $argumentTypeInfo->getName();
  57946. if (str_contains($typeAnalysisName, '|') || str_contains($typeAnalysisName, '&')) {
  57947. $this->fixUnionTypeParameter($tokens, $argumentTypeInfo);
  57948. } else {
  57949. $this->fixSingleTypeParameter($tokens, $argumentTypeInfo);
  57950. }
  57951. }
  57952. }
  57953. private function fixSingleTypeParameter(Tokens $tokens, TypeAnalysis $argumentTypeInfo): void
  57954. {
  57955. if (true === $this->configuration['use_nullable_type_declaration']) {
  57956. if (!$argumentTypeInfo->isNullable()) {
  57957. $tokens->insertAt($argumentTypeInfo->getStartIndex(), new Token([CT::T_NULLABLE_TYPE, '?']));
  57958. }
  57959. } elseif ($argumentTypeInfo->isNullable()) {
  57960. $tokens->removeTrailingWhitespace($startIndex = $argumentTypeInfo->getStartIndex());
  57961. $tokens->clearTokenAndMergeSurroundingWhitespace($startIndex);
  57962. }
  57963. }
  57964. private function fixUnionTypeParameter(Tokens $tokens, TypeAnalysis $argumentTypeInfo): void
  57965. {
  57966. if (true === $this->configuration['use_nullable_type_declaration']) {
  57967. if ($argumentTypeInfo->isNullable()) {
  57968. return;
  57969. }
  57970. $typeAnalysisName = $argumentTypeInfo->getName();
  57971. $endIndex = $argumentTypeInfo->getEndIndex();
  57972. if (str_contains($typeAnalysisName, '&') && !str_contains($typeAnalysisName, '|')) {
  57973. $endIndex += 2;
  57974. $tokens->insertAt($argumentTypeInfo->getStartIndex(), new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, '(']));
  57975. $tokens->insertAt($endIndex, new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE, ')']));
  57976. }
  57977. $tokens->insertAt($endIndex + 1, [
  57978. new Token([CT::T_TYPE_ALTERNATION, '|']),
  57979. new Token([T_STRING, 'null']),
  57980. ]);
  57981. } elseif ($argumentTypeInfo->isNullable()) {
  57982. $startIndex = $argumentTypeInfo->getStartIndex();
  57983. $index = $tokens->getNextTokenOfKind($startIndex - 1, [[T_STRING, 'null']], false);
  57984. if ($index === $startIndex) {
  57985. $tokens->removeTrailingWhitespace($index);
  57986. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  57987. $index = $tokens->getNextMeaningfulToken($index);
  57988. if ($tokens[$index]->equals([CT::T_TYPE_ALTERNATION, '|'])) {
  57989. $tokens->removeTrailingWhitespace($index);
  57990. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  57991. }
  57992. } else {
  57993. $tokens->removeLeadingWhitespace($index);
  57994. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  57995. $index = $tokens->getPrevMeaningfulToken($index);
  57996. if ($tokens[$index]->equals([CT::T_TYPE_ALTERNATION, '|'])) {
  57997. $tokens->removeLeadingWhitespace($index);
  57998. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  57999. }
  58000. }
  58001. $typeAnalysisName = $argumentTypeInfo->getName();
  58002. if (str_contains($typeAnalysisName, '&') && 1 === substr_count($typeAnalysisName, '|')) {
  58003. $index = $tokens->getNextTokenOfKind($startIndex - 1, [[CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN]]);
  58004. $tokens->removeTrailingWhitespace($index);
  58005. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  58006. $index = $tokens->getPrevTokenOfKind($argumentTypeInfo->getEndIndex() + 1, [[CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE]]);
  58007. $tokens->removeLeadingWhitespace($index);
  58008. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  58009. }
  58010. }
  58011. }
  58012. }
  58013. <?php
  58014. declare(strict_types=1);
  58015. namespace PhpCsFixer\Fixer\FunctionNotation;
  58016. use PhpCsFixer\AbstractFixer;
  58017. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  58018. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  58019. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  58020. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  58021. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  58022. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  58023. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  58024. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58025. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58026. use PhpCsFixer\FixerDefinition\VersionSpecification;
  58027. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  58028. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  58029. use PhpCsFixer\Tokenizer\CT;
  58030. use PhpCsFixer\Tokenizer\Tokens;
  58031. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  58032. /**
  58033. @phpstan-type
  58034. @phpstan-type
  58035. @phpstan-type
  58036. @phpstan-type
  58037. @phpstan-type
  58038. @implements
  58039. */
  58040. final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface, ExperimentalFixerInterface
  58041. {
  58042. /**
  58043. @use */
  58044. use ConfigurableFixerTrait;
  58045. public function getDefinition(): FixerDefinitionInterface
  58046. {
  58047. return new FixerDefinition(
  58048. 'Promoted properties must be on separate lines.',
  58049. [
  58050. new VersionSpecificCodeSample(
  58051. <<<'PHP'
  58052. <?php
  58053. class Foo {
  58054. public function __construct(private array $a, private bool $b, private int $i) {}
  58055. }
  58056. PHP,
  58057. new VersionSpecification(80_000),
  58058. ),
  58059. new VersionSpecificCodeSample(
  58060. <<<'PHP'
  58061. <?php
  58062. class Foo {
  58063. public function __construct(private array $a, private bool $b, private int $i) {}
  58064. }
  58065. class Bar {
  58066. public function __construct(private array $x) {}
  58067. }
  58068. PHP,
  58069. new VersionSpecification(80_000),
  58070. ['minimum_number_of_parameters' => 3]
  58071. ),
  58072. ],
  58073. );
  58074. }
  58075. public function getPriority(): int
  58076. {
  58077. return 1;
  58078. }
  58079. public function isCandidate(Tokens $tokens): bool
  58080. {
  58081. return $tokens->isAnyTokenKindsFound([
  58082. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  58083. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  58084. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  58085. ]);
  58086. }
  58087. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  58088. {
  58089. return new FixerConfigurationResolver([
  58090. (new FixerOptionBuilder('keep_blank_lines', 'Whether to keep blank lines between properties.'))
  58091. ->setAllowedTypes(['bool'])
  58092. ->setDefault(false)
  58093. ->getOption(),
  58094. (new FixerOptionBuilder('minimum_number_of_parameters', 'Minimum number of parameters in the constructor to fix.'))
  58095. ->setAllowedTypes(['int'])
  58096. ->setDefault(1)
  58097. ->getOption(),
  58098. ]);
  58099. }
  58100. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58101. {
  58102. $tokensAnalyzer = new TokensAnalyzer($tokens);
  58103. foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
  58104. if ('method' !== $element['type']) {
  58105. continue;
  58106. }
  58107. $openParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(']);
  58108. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  58109. if (!$this->shouldBeFixed($tokens, $openParenthesisIndex, $closeParenthesisIndex)) {
  58110. continue;
  58111. }
  58112. $this->fixParameters($tokens, $openParenthesisIndex, $closeParenthesisIndex);
  58113. }
  58114. }
  58115. private function shouldBeFixed(Tokens $tokens, int $openParenthesisIndex, int $closeParenthesisIndex): bool
  58116. {
  58117. $promotedParameterFound = false;
  58118. $minimumNumberOfParameters = 0;
  58119. for ($index = $openParenthesisIndex + 1; $index < $closeParenthesisIndex; ++$index) {
  58120. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  58121. ++$minimumNumberOfParameters;
  58122. }
  58123. if (
  58124. $tokens[$index]->isGivenKind([
  58125. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  58126. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  58127. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  58128. ])
  58129. ) {
  58130. $promotedParameterFound = true;
  58131. }
  58132. }
  58133. return $promotedParameterFound && $minimumNumberOfParameters >= $this->configuration['minimum_number_of_parameters'];
  58134. }
  58135. private function fixParameters(Tokens $tokens, int $openParenthesis, int $closeParenthesis): void
  58136. {
  58137. $indent = WhitespacesAnalyzer::detectIndent($tokens, $openParenthesis);
  58138. $tokens->ensureWhitespaceAtIndex(
  58139. $closeParenthesis - 1,
  58140. 1,
  58141. $this->whitespacesConfig->getLineEnding().$indent,
  58142. );
  58143. $index = $tokens->getPrevMeaningfulToken($closeParenthesis);
  58144. \assert(\is_int($index));
  58145. while ($index > $openParenthesis) {
  58146. $index = $tokens->getPrevMeaningfulToken($index);
  58147. \assert(\is_int($index));
  58148. $blockType = Tokens::detectBlockType($tokens[$index]);
  58149. if (null !== $blockType && !$blockType['isStart']) {
  58150. $index = $tokens->findBlockStart($blockType['type'], $index);
  58151. continue;
  58152. }
  58153. if (!$tokens[$index]->equalsAny(['(', ','])) {
  58154. continue;
  58155. }
  58156. $this->fixParameter($tokens, $index + 1, $indent);
  58157. }
  58158. }
  58159. private function fixParameter(Tokens $tokens, int $index, string $indent): void
  58160. {
  58161. if ($this->configuration['keep_blank_lines'] && $tokens[$index]->isWhitespace() && str_contains($tokens[$index]->getContent(), "\n")) {
  58162. return;
  58163. }
  58164. $tokens->ensureWhitespaceAtIndex(
  58165. $index,
  58166. 0,
  58167. $this->whitespacesConfig->getLineEnding().$indent.$this->whitespacesConfig->getIndent(),
  58168. );
  58169. }
  58170. }
  58171. <?php
  58172. declare(strict_types=1);
  58173. namespace PhpCsFixer\Fixer\FunctionNotation;
  58174. use PhpCsFixer\AbstractFixer;
  58175. use PhpCsFixer\FixerDefinition\CodeSample;
  58176. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58177. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58178. use PhpCsFixer\Tokenizer\CT;
  58179. use PhpCsFixer\Tokenizer\Tokens;
  58180. final class NoUnreachableDefaultArgumentValueFixer extends AbstractFixer
  58181. {
  58182. public function getDefinition(): FixerDefinitionInterface
  58183. {
  58184. return new FixerDefinition(
  58185. 'In function arguments there must not be arguments with default values before non-default ones.',
  58186. [
  58187. new CodeSample(
  58188. '<?php
  58189. function example($foo = "two words", $bar) {}
  58190. '
  58191. ),
  58192. ],
  58193. null,
  58194. 'Modifies the signature of functions; therefore risky when using systems (such as some Symfony components) that rely on those (for example through reflection).'
  58195. );
  58196. }
  58197. public function getPriority(): int
  58198. {
  58199. return 0;
  58200. }
  58201. public function isCandidate(Tokens $tokens): bool
  58202. {
  58203. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  58204. }
  58205. public function isRisky(): bool
  58206. {
  58207. return true;
  58208. }
  58209. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58210. {
  58211. $functionKinds = [T_FUNCTION, T_FN];
  58212. for ($i = 0, $l = $tokens->count(); $i < $l; ++$i) {
  58213. if (!$tokens[$i]->isGivenKind($functionKinds)) {
  58214. continue;
  58215. }
  58216. $startIndex = $tokens->getNextTokenOfKind($i, ['(']);
  58217. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  58218. $this->fixFunctionDefinition($tokens, $startIndex, $i);
  58219. }
  58220. }
  58221. private function fixFunctionDefinition(Tokens $tokens, int $startIndex, int $endIndex): void
  58222. {
  58223. $lastArgumentIndex = $this->getLastNonDefaultArgumentIndex($tokens, $startIndex, $endIndex);
  58224. if (null === $lastArgumentIndex) {
  58225. return;
  58226. }
  58227. for ($i = $lastArgumentIndex; $i > $startIndex; --$i) {
  58228. $token = $tokens[$i];
  58229. if ($token->isGivenKind(T_VARIABLE)) {
  58230. $lastArgumentIndex = $i;
  58231. continue;
  58232. }
  58233. if (!$token->equals('=') || $this->isNonNullableTypehintedNullableVariable($tokens, $i)) {
  58234. continue;
  58235. }
  58236. $this->removeDefaultValue($tokens, $i, $this->getDefaultValueEndIndex($tokens, $lastArgumentIndex));
  58237. }
  58238. }
  58239. private function getLastNonDefaultArgumentIndex(Tokens $tokens, int $startIndex, int $endIndex): ?int
  58240. {
  58241. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  58242. $token = $tokens[$i];
  58243. if ($token->equals('=')) {
  58244. $i = $tokens->getPrevMeaningfulToken($i);
  58245. continue;
  58246. }
  58247. if ($token->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_CLOSE)) {
  58248. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PROPERTY_HOOK, $i);
  58249. continue;
  58250. }
  58251. if ($token->isGivenKind(T_VARIABLE) && !$this->isEllipsis($tokens, $i)) {
  58252. return $i;
  58253. }
  58254. }
  58255. return null;
  58256. }
  58257. private function isEllipsis(Tokens $tokens, int $variableIndex): bool
  58258. {
  58259. return $tokens[$tokens->getPrevMeaningfulToken($variableIndex)]->isGivenKind(T_ELLIPSIS);
  58260. }
  58261. private function getDefaultValueEndIndex(Tokens $tokens, int $index): int
  58262. {
  58263. do {
  58264. $index = $tokens->getPrevMeaningfulToken($index);
  58265. if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  58266. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  58267. }
  58268. } while (!$tokens[$index]->equals(','));
  58269. return $tokens->getPrevMeaningfulToken($index);
  58270. }
  58271. private function removeDefaultValue(Tokens $tokens, int $startIndex, int $endIndex): void
  58272. {
  58273. for ($i = $startIndex; $i <= $endIndex;) {
  58274. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  58275. $this->clearWhitespacesBeforeIndex($tokens, $i);
  58276. $i = $tokens->getNextMeaningfulToken($i);
  58277. }
  58278. }
  58279. private function isNonNullableTypehintedNullableVariable(Tokens $tokens, int $index): bool
  58280. {
  58281. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  58282. if (!$nextToken->equals([T_STRING, 'null'], false)) {
  58283. return false;
  58284. }
  58285. $variableIndex = $tokens->getPrevMeaningfulToken($index);
  58286. $searchTokens = [',', '(', [T_STRING], [CT::T_ARRAY_TYPEHINT], [T_CALLABLE]];
  58287. $typehintKinds = [T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE];
  58288. $prevIndex = $tokens->getPrevTokenOfKind($variableIndex, $searchTokens);
  58289. if (!$tokens[$prevIndex]->isGivenKind($typehintKinds)) {
  58290. return false;
  58291. }
  58292. return !$tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isGivenKind(CT::T_NULLABLE_TYPE);
  58293. }
  58294. private function clearWhitespacesBeforeIndex(Tokens $tokens, int $index): void
  58295. {
  58296. $prevIndex = $tokens->getNonEmptySibling($index, -1);
  58297. if (!$tokens[$prevIndex]->isWhitespace()) {
  58298. return;
  58299. }
  58300. $prevNonWhiteIndex = $tokens->getPrevNonWhitespace($prevIndex);
  58301. if (null === $prevNonWhiteIndex || !$tokens[$prevNonWhiteIndex]->isComment()) {
  58302. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  58303. }
  58304. }
  58305. }
  58306. <?php
  58307. declare(strict_types=1);
  58308. namespace PhpCsFixer\Fixer\FunctionNotation;
  58309. use PhpCsFixer\AbstractPhpdocToTypeDeclarationFixer;
  58310. use PhpCsFixer\DocBlock\Annotation;
  58311. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  58312. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  58313. use PhpCsFixer\FixerDefinition\CodeSample;
  58314. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58315. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58316. use PhpCsFixer\Tokenizer\Token;
  58317. use PhpCsFixer\Tokenizer\Tokens;
  58318. /**
  58319. @phpstan-type
  58320. @phpstan-type
  58321. @implements
  58322. */
  58323. final class PhpdocToParamTypeFixer extends AbstractPhpdocToTypeDeclarationFixer implements ConfigurableFixerInterface, ExperimentalFixerInterface
  58324. {
  58325. private const TYPE_CHECK_TEMPLATE = '<?php function f(%s $x) {}';
  58326. private const EXCLUDE_FUNC_NAMES = [
  58327. [T_STRING, '__clone'],
  58328. [T_STRING, '__destruct'],
  58329. ];
  58330. private const SKIPPED_TYPES = [
  58331. 'resource' => true,
  58332. 'static' => true,
  58333. 'void' => true,
  58334. ];
  58335. public function getDefinition(): FixerDefinitionInterface
  58336. {
  58337. return new FixerDefinition(
  58338. 'Takes `@param` annotations of non-mixed types and adjusts accordingly the function signature.',
  58339. [
  58340. new CodeSample(
  58341. '<?php
  58342. /**
  58343. * @param string $foo
  58344. * @param string|null $bar
  58345. */
  58346. function f($foo, $bar)
  58347. {}
  58348. '
  58349. ),
  58350. new CodeSample(
  58351. '<?php
  58352. /** @param Foo $foo */
  58353. function foo($foo) {}
  58354. /** @param string $foo */
  58355. function bar($foo) {}
  58356. ',
  58357. ['scalar_types' => false]
  58358. ),
  58359. new CodeSample(
  58360. '<?php
  58361. /** @param Foo $foo */
  58362. function foo($foo) {}
  58363. /** @param int|string $foo */
  58364. function bar($foo) {}
  58365. ',
  58366. ['union_types' => false]
  58367. ),
  58368. ],
  58369. null,
  58370. 'The `@param` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. Manual actions are required if inherited signatures are not properly documented.'
  58371. );
  58372. }
  58373. public function isCandidate(Tokens $tokens): bool
  58374. {
  58375. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  58376. }
  58377. public function getPriority(): int
  58378. {
  58379. return 8;
  58380. }
  58381. protected function isSkippedType(string $type): bool
  58382. {
  58383. return isset(self::SKIPPED_TYPES[$type]);
  58384. }
  58385. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58386. {
  58387. for ($index = $tokens->count() - 1; 0 < $index; --$index) {
  58388. if (!$tokens[$index]->isGivenKind([T_FUNCTION, T_FN])) {
  58389. continue;
  58390. }
  58391. $funcName = $tokens->getNextMeaningfulToken($index);
  58392. if ($tokens[$funcName]->equalsAny(self::EXCLUDE_FUNC_NAMES, false)) {
  58393. continue;
  58394. }
  58395. $docCommentIndex = $this->findFunctionDocComment($tokens, $index);
  58396. if (null === $docCommentIndex) {
  58397. continue;
  58398. }
  58399. foreach ($this->getAnnotationsFromDocComment('param', $tokens, $docCommentIndex) as $paramTypeAnnotation) {
  58400. $typesExpression = $paramTypeAnnotation->getTypeExpression();
  58401. if (null === $typesExpression) {
  58402. continue;
  58403. }
  58404. $typeInfo = $this->getCommonTypeInfo($typesExpression, false);
  58405. $unionTypes = null;
  58406. if (null === $typeInfo) {
  58407. $unionTypes = $this->getUnionTypes($typesExpression, false);
  58408. }
  58409. if (null === $typeInfo && null === $unionTypes) {
  58410. continue;
  58411. }
  58412. if (null !== $typeInfo) {
  58413. $paramType = $typeInfo['commonType'];
  58414. $isNullable = $typeInfo['isNullable'];
  58415. } elseif (null !== $unionTypes) {
  58416. $paramType = $unionTypes;
  58417. $isNullable = false;
  58418. }
  58419. if (!isset($paramType, $isNullable)) {
  58420. continue;
  58421. }
  58422. $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
  58423. $variableIndex = $this->findCorrectVariable($tokens, $startIndex, $paramTypeAnnotation);
  58424. if (null === $variableIndex) {
  58425. continue;
  58426. }
  58427. $byRefIndex = $tokens->getPrevMeaningfulToken($variableIndex);
  58428. if ($tokens[$byRefIndex]->equals('&')) {
  58429. $variableIndex = $byRefIndex;
  58430. }
  58431. if ($this->hasParamTypeHint($tokens, $variableIndex)) {
  58432. continue;
  58433. }
  58434. if (!$this->isValidSyntax(\sprintf(self::TYPE_CHECK_TEMPLATE, $paramType))) {
  58435. continue;
  58436. }
  58437. $tokens->insertAt($variableIndex, array_merge(
  58438. $this->createTypeDeclarationTokens($paramType, $isNullable),
  58439. [new Token([T_WHITESPACE, ' '])]
  58440. ));
  58441. }
  58442. }
  58443. }
  58444. protected function createTokensFromRawType(string $type): Tokens
  58445. {
  58446. $typeTokens = Tokens::fromCode(\sprintf(self::TYPE_CHECK_TEMPLATE, $type));
  58447. $typeTokens->clearRange(0, 4);
  58448. $typeTokens->clearRange(\count($typeTokens) - 6, \count($typeTokens) - 1);
  58449. $typeTokens->clearEmptyTokens();
  58450. return $typeTokens;
  58451. }
  58452. private function findCorrectVariable(Tokens $tokens, int $startIndex, Annotation $paramTypeAnnotation): ?int
  58453. {
  58454. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  58455. for ($index = $startIndex + 1; $index < $endIndex; ++$index) {
  58456. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  58457. continue;
  58458. }
  58459. $variableName = $tokens[$index]->getContent();
  58460. if ($paramTypeAnnotation->getVariableName() === $variableName) {
  58461. return $index;
  58462. }
  58463. }
  58464. return null;
  58465. }
  58466. private function hasParamTypeHint(Tokens $tokens, int $index): bool
  58467. {
  58468. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  58469. return !$tokens[$prevIndex]->equalsAny([',', '(']);
  58470. }
  58471. }
  58472. <?php
  58473. declare(strict_types=1);
  58474. namespace PhpCsFixer\Fixer\FunctionNotation;
  58475. use PhpCsFixer\AbstractFixer;
  58476. use PhpCsFixer\FixerDefinition\CodeSample;
  58477. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58478. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58479. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  58480. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  58481. use PhpCsFixer\Tokenizer\Token;
  58482. use PhpCsFixer\Tokenizer\Tokens;
  58483. final class ImplodeCallFixer extends AbstractFixer
  58484. {
  58485. public function getDefinition(): FixerDefinitionInterface
  58486. {
  58487. return new FixerDefinition(
  58488. 'Function `implode` must be called with 2 arguments in the documented order.',
  58489. [
  58490. new CodeSample("<?php\nimplode(\$pieces, '');\n"),
  58491. new CodeSample("<?php\nimplode(\$pieces);\n"),
  58492. ],
  58493. null,
  58494. 'Risky when the function `implode` is overridden.'
  58495. );
  58496. }
  58497. public function isRisky(): bool
  58498. {
  58499. return true;
  58500. }
  58501. public function isCandidate(Tokens $tokens): bool
  58502. {
  58503. return $tokens->isTokenKindFound(T_STRING);
  58504. }
  58505. public function getPriority(): int
  58506. {
  58507. return 37;
  58508. }
  58509. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58510. {
  58511. $functionsAnalyzer = new FunctionsAnalyzer();
  58512. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  58513. if (!$tokens[$index]->equals([T_STRING, 'implode'], false)) {
  58514. continue;
  58515. }
  58516. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  58517. continue;
  58518. }
  58519. $argumentsIndices = $this->getArgumentIndices($tokens, $index);
  58520. if (1 === \count($argumentsIndices)) {
  58521. $firstArgumentIndex = array_key_first($argumentsIndices);
  58522. $tokens->insertAt($firstArgumentIndex, [
  58523. new Token([T_CONSTANT_ENCAPSED_STRING, "''"]),
  58524. new Token(','),
  58525. new Token([T_WHITESPACE, ' ']),
  58526. ]);
  58527. continue;
  58528. }
  58529. if (2 === \count($argumentsIndices)) {
  58530. [$firstArgumentIndex, $secondArgumentIndex] = array_keys($argumentsIndices);
  58531. if ($tokens[$firstArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  58532. continue;
  58533. }
  58534. if (!$tokens[$secondArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  58535. continue;
  58536. }
  58537. $firstArgumentEndIndex = $argumentsIndices[key($argumentsIndices)];
  58538. $newSecondArgumentTokens = [];
  58539. for ($i = array_key_first($argumentsIndices); $i <= $firstArgumentEndIndex; ++$i) {
  58540. $newSecondArgumentTokens[] = clone $tokens[$i];
  58541. $tokens->clearAt($i);
  58542. }
  58543. $tokens->insertAt($firstArgumentIndex, clone $tokens[$secondArgumentIndex]);
  58544. ++$secondArgumentIndex;
  58545. $tokens->clearAt($secondArgumentIndex);
  58546. $tokens->insertAt($secondArgumentIndex, $newSecondArgumentTokens);
  58547. }
  58548. }
  58549. }
  58550. private function getArgumentIndices(Tokens $tokens, int $functionNameIndex): array
  58551. {
  58552. $argumentsAnalyzer = new ArgumentsAnalyzer();
  58553. $openParenthesis = $tokens->getNextTokenOfKind($functionNameIndex, ['(']);
  58554. $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
  58555. $indices = [];
  58556. foreach ($argumentsAnalyzer->getArguments($tokens, $openParenthesis, $closeParenthesis) as $startIndexCandidate => $endIndex) {
  58557. $indices[$tokens->getNextMeaningfulToken($startIndexCandidate - 1)] = $tokens->getPrevMeaningfulToken($endIndex + 1);
  58558. }
  58559. return $indices;
  58560. }
  58561. }
  58562. <?php
  58563. declare(strict_types=1);
  58564. namespace PhpCsFixer\Fixer\FunctionNotation;
  58565. use PhpCsFixer\AbstractFixer;
  58566. use PhpCsFixer\FixerDefinition\CodeSample;
  58567. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58568. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58569. use PhpCsFixer\Tokenizer\CT;
  58570. use PhpCsFixer\Tokenizer\Token;
  58571. use PhpCsFixer\Tokenizer\Tokens;
  58572. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  58573. final class UseArrowFunctionsFixer extends AbstractFixer
  58574. {
  58575. public function getDefinition(): FixerDefinitionInterface
  58576. {
  58577. return new FixerDefinition(
  58578. 'Anonymous functions with return as the only statement must use arrow functions.',
  58579. [
  58580. new CodeSample(
  58581. <<<'SAMPLE'
  58582. <?php
  58583. foo(function ($a) use ($b) {
  58584. return $a + $b;
  58585. });
  58586. SAMPLE
  58587. ,
  58588. ),
  58589. ],
  58590. null,
  58591. 'Risky when using `isset()` on outside variables that are not imported with `use ()`.'
  58592. );
  58593. }
  58594. public function isCandidate(Tokens $tokens): bool
  58595. {
  58596. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN]);
  58597. }
  58598. public function isRisky(): bool
  58599. {
  58600. return true;
  58601. }
  58602. public function getPriority(): int
  58603. {
  58604. return 32;
  58605. }
  58606. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58607. {
  58608. $analyzer = new TokensAnalyzer($tokens);
  58609. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  58610. if (!$tokens[$index]->isGivenKind(T_FUNCTION) || !$analyzer->isLambda($index)) {
  58611. continue;
  58612. }
  58613. $parametersStart = $tokens->getNextMeaningfulToken($index);
  58614. if ($tokens[$parametersStart]->isGivenKind(CT::T_RETURN_REF)) {
  58615. $parametersStart = $tokens->getNextMeaningfulToken($parametersStart);
  58616. }
  58617. $parametersEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $parametersStart);
  58618. $next = $tokens->getNextMeaningfulToken($parametersEnd);
  58619. $useStart = null;
  58620. $useEnd = null;
  58621. if ($tokens[$next]->isGivenKind(CT::T_USE_LAMBDA)) {
  58622. $useStart = $next;
  58623. if ($tokens[$useStart - 1]->isGivenKind(T_WHITESPACE)) {
  58624. --$useStart;
  58625. }
  58626. $next = $tokens->getNextMeaningfulToken($next);
  58627. while (!$tokens[$next]->equals(')')) {
  58628. if ($tokens[$next]->equals('&')) {
  58629. continue 2;
  58630. }
  58631. $next = $tokens->getNextMeaningfulToken($next);
  58632. }
  58633. $useEnd = $next;
  58634. $next = $tokens->getNextMeaningfulToken($next);
  58635. }
  58636. $braceOpen = $tokens[$next]->equals('{') ? $next : $tokens->getNextTokenOfKind($next, ['{']);
  58637. $return = $braceOpen + 1;
  58638. if ($tokens[$return]->isGivenKind(T_WHITESPACE)) {
  58639. ++$return;
  58640. }
  58641. if (!$tokens[$return]->isGivenKind(T_RETURN)) {
  58642. continue;
  58643. }
  58644. $semicolon = $tokens->getNextTokenOfKind($return, ['{', ';']);
  58645. if (!$tokens[$semicolon]->equals(';')) {
  58646. continue;
  58647. }
  58648. $braceClose = $semicolon + 1;
  58649. if ($tokens[$braceClose]->isGivenKind(T_WHITESPACE)) {
  58650. ++$braceClose;
  58651. }
  58652. if (!$tokens[$braceClose]->equals('}')) {
  58653. continue;
  58654. }
  58655. $this->transform($tokens, $index, $useStart, $useEnd, $braceOpen, $return, $semicolon, $braceClose);
  58656. }
  58657. }
  58658. private function transform(Tokens $tokens, int $index, ?int $useStart, ?int $useEnd, int $braceOpen, int $return, int $semicolon, int $braceClose): void
  58659. {
  58660. $tokensToInsert = [new Token([T_DOUBLE_ARROW, '=>'])];
  58661. if ($tokens->getNextMeaningfulToken($return) === $semicolon) {
  58662. $tokensToInsert[] = new Token([T_WHITESPACE, ' ']);
  58663. $tokensToInsert[] = new Token([T_STRING, 'null']);
  58664. }
  58665. $tokens->clearRange($semicolon, $braceClose);
  58666. $tokens->clearRange($braceOpen + 1, $return);
  58667. $tokens->overrideRange($braceOpen, $braceOpen, $tokensToInsert);
  58668. if (null !== $useStart) {
  58669. $tokens->clearRange($useStart, $useEnd);
  58670. }
  58671. $tokens[$index] = new Token([T_FN, 'fn']);
  58672. }
  58673. }
  58674. <?php
  58675. declare(strict_types=1);
  58676. namespace PhpCsFixer\Fixer\FunctionNotation;
  58677. use PhpCsFixer\AbstractFixer;
  58678. use PhpCsFixer\FixerDefinition\CodeSample;
  58679. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58680. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58681. use PhpCsFixer\Preg;
  58682. use PhpCsFixer\Tokenizer\Token;
  58683. use PhpCsFixer\Tokenizer\Tokens;
  58684. final class SingleLineThrowFixer extends AbstractFixer
  58685. {
  58686. private const REMOVE_WHITESPACE_AFTER_TOKENS = ['['];
  58687. private const REMOVE_WHITESPACE_AROUND_TOKENS = ['(', [T_DOUBLE_COLON]];
  58688. private const REMOVE_WHITESPACE_BEFORE_TOKENS = [')', ']', ',', ';'];
  58689. public function getDefinition(): FixerDefinitionInterface
  58690. {
  58691. return new FixerDefinition(
  58692. 'Throwing exception must be done in single line.',
  58693. [
  58694. new CodeSample("<?php\nthrow new Exception(\n 'Error.',\n 500\n);\n"),
  58695. ]
  58696. );
  58697. }
  58698. public function isCandidate(Tokens $tokens): bool
  58699. {
  58700. return $tokens->isTokenKindFound(T_THROW);
  58701. }
  58702. public function getPriority(): int
  58703. {
  58704. return 36;
  58705. }
  58706. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58707. {
  58708. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  58709. if (!$tokens[$index]->isGivenKind(T_THROW)) {
  58710. continue;
  58711. }
  58712. $endCandidateIndex = $tokens->getNextMeaningfulToken($index);
  58713. while (!$tokens[$endCandidateIndex]->equalsAny([')', ']', ',', ';', [T_CLOSE_TAG]])) {
  58714. $blockType = Tokens::detectBlockType($tokens[$endCandidateIndex]);
  58715. if (null !== $blockType) {
  58716. if (Tokens::BLOCK_TYPE_CURLY_BRACE === $blockType['type'] || !$blockType['isStart']) {
  58717. break;
  58718. }
  58719. $endCandidateIndex = $tokens->findBlockEnd($blockType['type'], $endCandidateIndex);
  58720. }
  58721. $endCandidateIndex = $tokens->getNextMeaningfulToken($endCandidateIndex);
  58722. }
  58723. $this->trimNewLines($tokens, $index, $tokens->getPrevMeaningfulToken($endCandidateIndex));
  58724. }
  58725. }
  58726. private function trimNewLines(Tokens $tokens, int $startIndex, int $endIndex): void
  58727. {
  58728. for ($index = $startIndex; $index < $endIndex; ++$index) {
  58729. $content = $tokens[$index]->getContent();
  58730. if ($tokens[$index]->isGivenKind(T_COMMENT)) {
  58731. if (str_starts_with($content, '//')) {
  58732. $content = '/*'.substr($content, 2).' */';
  58733. $tokens->clearAt($index + 1);
  58734. } elseif (str_starts_with($content, '#')) {
  58735. $content = '/*'.substr($content, 1).' */';
  58736. $tokens->clearAt($index + 1);
  58737. } elseif (Preg::match('/\R/', $content)) {
  58738. $content = Preg::replace('/\R/', ' ', $content);
  58739. }
  58740. $tokens[$index] = new Token([T_COMMENT, $content]);
  58741. continue;
  58742. }
  58743. if (!$tokens[$index]->isGivenKind(T_WHITESPACE)) {
  58744. continue;
  58745. }
  58746. if (!Preg::match('/\R/', $content)) {
  58747. continue;
  58748. }
  58749. $prevIndex = $tokens->getNonEmptySibling($index, -1);
  58750. if ($this->isPreviousTokenToClear($tokens[$prevIndex])) {
  58751. $tokens->clearAt($index);
  58752. continue;
  58753. }
  58754. $nextIndex = $tokens->getNonEmptySibling($index, 1);
  58755. if (
  58756. $this->isNextTokenToClear($tokens[$nextIndex])
  58757. && !$tokens[$prevIndex]->isGivenKind(T_FUNCTION)
  58758. ) {
  58759. $tokens->clearAt($index);
  58760. continue;
  58761. }
  58762. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  58763. }
  58764. }
  58765. private function isPreviousTokenToClear(Token $token): bool
  58766. {
  58767. static $tokens = null;
  58768. if (null === $tokens) {
  58769. $tokens = [...self::REMOVE_WHITESPACE_AFTER_TOKENS, ...self::REMOVE_WHITESPACE_AROUND_TOKENS];
  58770. }
  58771. return $token->equalsAny($tokens) || $token->isObjectOperator();
  58772. }
  58773. private function isNextTokenToClear(Token $token): bool
  58774. {
  58775. static $tokens = null;
  58776. if (null === $tokens) {
  58777. $tokens = [...self::REMOVE_WHITESPACE_AROUND_TOKENS, ...self::REMOVE_WHITESPACE_BEFORE_TOKENS];
  58778. }
  58779. return $token->equalsAny($tokens) || $token->isObjectOperator();
  58780. }
  58781. }
  58782. <?php
  58783. declare(strict_types=1);
  58784. namespace PhpCsFixer\Fixer\FunctionNotation;
  58785. use PhpCsFixer\AbstractFixer;
  58786. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  58787. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  58788. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  58789. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  58790. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  58791. use PhpCsFixer\FixerDefinition\CodeSample;
  58792. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58793. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58794. use PhpCsFixer\Tokenizer\CT;
  58795. use PhpCsFixer\Tokenizer\Tokens;
  58796. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  58797. /**
  58798. @phpstan-type
  58799. @phpstan-type
  58800. @implements
  58801. */
  58802. final class FunctionDeclarationFixer extends AbstractFixer implements ConfigurableFixerInterface
  58803. {
  58804. /**
  58805. @use */
  58806. use ConfigurableFixerTrait;
  58807. public const SPACING_NONE = 'none';
  58808. public const SPACING_ONE = 'one';
  58809. private const SUPPORTED_SPACINGS = [self::SPACING_NONE, self::SPACING_ONE];
  58810. private string $singleLineWhitespaceOptions = " \t";
  58811. public function isCandidate(Tokens $tokens): bool
  58812. {
  58813. return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
  58814. }
  58815. public function getDefinition(): FixerDefinitionInterface
  58816. {
  58817. return new FixerDefinition(
  58818. 'Spaces should be properly placed in a function declaration.',
  58819. [
  58820. new CodeSample(
  58821. '<?php
  58822. class Foo
  58823. {
  58824. public static function bar ( $baz , $foo )
  58825. {
  58826. return false;
  58827. }
  58828. }
  58829. function foo ($bar, $baz)
  58830. {
  58831. return false;
  58832. }
  58833. '
  58834. ),
  58835. new CodeSample(
  58836. '<?php
  58837. $f = function () {};
  58838. ',
  58839. ['closure_function_spacing' => self::SPACING_NONE]
  58840. ),
  58841. new CodeSample(
  58842. '<?php
  58843. $f = fn () => null;
  58844. ',
  58845. ['closure_fn_spacing' => self::SPACING_NONE]
  58846. ),
  58847. ]
  58848. );
  58849. }
  58850. public function getPriority(): int
  58851. {
  58852. return 31;
  58853. }
  58854. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  58855. {
  58856. $tokensAnalyzer = new TokensAnalyzer($tokens);
  58857. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  58858. $token = $tokens[$index];
  58859. if (!$token->isGivenKind([T_FUNCTION, T_FN])) {
  58860. continue;
  58861. }
  58862. $startParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(', ';', [T_CLOSE_TAG]]);
  58863. if (!$tokens[$startParenthesisIndex]->equals('(')) {
  58864. continue;
  58865. }
  58866. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
  58867. if (false === $this->configuration['trailing_comma_single_line']
  58868. && !$tokens->isPartialCodeMultiline($index, $endParenthesisIndex)
  58869. ) {
  58870. $commaIndex = $tokens->getPrevMeaningfulToken($endParenthesisIndex);
  58871. if ($tokens[$commaIndex]->equals(',')) {
  58872. $tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
  58873. }
  58874. }
  58875. $startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, [';', '{', [T_DOUBLE_ARROW]]);
  58876. if (
  58877. $tokens[$startBraceIndex]->equalsAny(['{', [T_DOUBLE_ARROW]])
  58878. && (
  58879. !$tokens[$startBraceIndex - 1]->isWhitespace()
  58880. || $tokens[$startBraceIndex - 1]->isWhitespace($this->singleLineWhitespaceOptions)
  58881. )
  58882. ) {
  58883. $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
  58884. }
  58885. $afterParenthesisIndex = $tokens->getNextNonWhitespace($endParenthesisIndex);
  58886. $afterParenthesisToken = $tokens[$afterParenthesisIndex];
  58887. if ($afterParenthesisToken->isGivenKind(CT::T_USE_LAMBDA)) {
  58888. $tokens->ensureWhitespaceAtIndex($afterParenthesisIndex + 1, 0, ' ');
  58889. $useStartParenthesisIndex = $tokens->getNextTokenOfKind($afterParenthesisIndex, ['(']);
  58890. $useEndParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $useStartParenthesisIndex);
  58891. if (false === $this->configuration['trailing_comma_single_line']
  58892. && !$tokens->isPartialCodeMultiline($index, $useEndParenthesisIndex)
  58893. ) {
  58894. $commaIndex = $tokens->getPrevMeaningfulToken($useEndParenthesisIndex);
  58895. if ($tokens[$commaIndex]->equals(',')) {
  58896. $tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
  58897. }
  58898. }
  58899. $this->fixParenthesisInnerEdge($tokens, $useStartParenthesisIndex, $useEndParenthesisIndex);
  58900. $tokens->ensureWhitespaceAtIndex($afterParenthesisIndex - 1, 1, ' ');
  58901. }
  58902. $this->fixParenthesisInnerEdge($tokens, $startParenthesisIndex, $endParenthesisIndex);
  58903. $isLambda = $tokensAnalyzer->isLambda($index);
  58904. if (!$isLambda && $tokens[$startParenthesisIndex - 1]->isWhitespace() && !$tokens[$tokens->getPrevNonWhitespace($startParenthesisIndex - 1)]->isComment()) {
  58905. $tokens->clearAt($startParenthesisIndex - 1);
  58906. }
  58907. $option = $token->isGivenKind(T_FN) ? 'closure_fn_spacing' : 'closure_function_spacing';
  58908. if ($isLambda && self::SPACING_NONE === $this->configuration[$option]) {
  58909. if ($tokens[$index + 1]->isWhitespace()) {
  58910. $tokens->clearAt($index + 1);
  58911. }
  58912. } else {
  58913. $tokens->ensureWhitespaceAtIndex($index + 1, 0, ' ');
  58914. }
  58915. if ($isLambda) {
  58916. $prev = $tokens->getPrevMeaningfulToken($index);
  58917. if ($tokens[$prev]->isGivenKind(T_STATIC)) {
  58918. $tokens->ensureWhitespaceAtIndex($prev + 1, 0, ' ');
  58919. }
  58920. }
  58921. }
  58922. }
  58923. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  58924. {
  58925. return new FixerConfigurationResolver([
  58926. (new FixerOptionBuilder('closure_function_spacing', 'Spacing to use before open parenthesis for closures.'))
  58927. ->setDefault(self::SPACING_ONE)
  58928. ->setAllowedValues(self::SUPPORTED_SPACINGS)
  58929. ->getOption(),
  58930. (new FixerOptionBuilder('closure_fn_spacing', 'Spacing to use before open parenthesis for short arrow functions.'))
  58931. ->setDefault(self::SPACING_ONE)
  58932. ->setAllowedValues(self::SUPPORTED_SPACINGS)
  58933. ->getOption(),
  58934. (new FixerOptionBuilder('trailing_comma_single_line', 'Whether trailing commas are allowed in single line signatures.'))
  58935. ->setAllowedTypes(['bool'])
  58936. ->setDefault(false)
  58937. ->getOption(),
  58938. ]);
  58939. }
  58940. private function fixParenthesisInnerEdge(Tokens $tokens, int $start, int $end): void
  58941. {
  58942. do {
  58943. --$end;
  58944. } while ($tokens->isEmptyAt($end));
  58945. if ($tokens[$end]->isWhitespace($this->singleLineWhitespaceOptions)) {
  58946. $tokens->clearAt($end);
  58947. }
  58948. if ($tokens[$start + 1]->isWhitespace($this->singleLineWhitespaceOptions)) {
  58949. $tokens->clearAt($start + 1);
  58950. }
  58951. }
  58952. }
  58953. <?php
  58954. declare(strict_types=1);
  58955. namespace PhpCsFixer\Fixer\Phpdoc;
  58956. use PhpCsFixer\AbstractFixer;
  58957. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  58958. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  58959. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  58960. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  58961. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  58962. use PhpCsFixer\FixerDefinition\CodeSample;
  58963. use PhpCsFixer\FixerDefinition\FixerDefinition;
  58964. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  58965. use PhpCsFixer\Preg;
  58966. use PhpCsFixer\Tokenizer\Token;
  58967. use PhpCsFixer\Tokenizer\Tokens;
  58968. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  58969. use Symfony\Component\OptionsResolver\Options;
  58970. /**
  58971. @phpstan-type
  58972. @phpstan-type
  58973. @implements
  58974. */
  58975. final class GeneralPhpdocTagRenameFixer extends AbstractFixer implements ConfigurableFixerInterface
  58976. {
  58977. /**
  58978. @use */
  58979. use ConfigurableFixerTrait;
  58980. public function getDefinition(): FixerDefinitionInterface
  58981. {
  58982. return new FixerDefinition(
  58983. 'Renames PHPDoc tags.',
  58984. [
  58985. new CodeSample("<?php\n/**\n * @inheritDocs\n * {@inheritdocs}\n */\n", [
  58986. 'replacements' => [
  58987. 'inheritDocs' => 'inheritDoc',
  58988. ],
  58989. ]),
  58990. new CodeSample("<?php\n/**\n * @inheritDocs\n * {@inheritdocs}\n */\n", [
  58991. 'replacements' => [
  58992. 'inheritDocs' => 'inheritDoc',
  58993. ],
  58994. 'fix_annotation' => false,
  58995. ]),
  58996. new CodeSample("<?php\n/**\n * @inheritDocs\n * {@inheritdocs}\n */\n", [
  58997. 'replacements' => [
  58998. 'inheritDocs' => 'inheritDoc',
  58999. ],
  59000. 'fix_inline' => false,
  59001. ]),
  59002. new CodeSample("<?php\n/**\n * @inheritDocs\n * {@inheritdocs}\n */\n", [
  59003. 'replacements' => [
  59004. 'inheritDocs' => 'inheritDoc',
  59005. ],
  59006. 'case_sensitive' => true,
  59007. ]),
  59008. ]
  59009. );
  59010. }
  59011. public function getPriority(): int
  59012. {
  59013. return 11;
  59014. }
  59015. public function isCandidate(Tokens $tokens): bool
  59016. {
  59017. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59018. }
  59019. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  59020. {
  59021. return new FixerConfigurationResolver([
  59022. (new FixerOptionBuilder('fix_annotation', 'Whether annotation tags should be fixed.'))
  59023. ->setAllowedTypes(['bool'])
  59024. ->setDefault(true)
  59025. ->getOption(),
  59026. (new FixerOptionBuilder('fix_inline', 'Whether inline tags should be fixed.'))
  59027. ->setAllowedTypes(['bool'])
  59028. ->setDefault(true)
  59029. ->getOption(),
  59030. (new FixerOptionBuilder('replacements', 'A map of tags to replace.'))
  59031. ->setAllowedTypes(['array<string, string>'])
  59032. ->setNormalizer(static function (Options $options, array $value): array {
  59033. $normalizedValue = [];
  59034. foreach ($value as $from => $to) {
  59035. if (!\is_string($from)) {
  59036. throw new InvalidOptionsException('Tag to replace must be a string.');
  59037. }
  59038. if (!Preg::match('#^\S+$#', $to) || str_contains($to, '*/')) {
  59039. throw new InvalidOptionsException(\sprintf(
  59040. 'Tag "%s" cannot be replaced by invalid tag "%s".',
  59041. $from,
  59042. $to
  59043. ));
  59044. }
  59045. $from = trim($from);
  59046. $to = trim($to);
  59047. if (false === $options['case_sensitive']) {
  59048. $lowercaseFrom = strtolower($from);
  59049. if (isset($normalizedValue[$lowercaseFrom]) && $normalizedValue[$lowercaseFrom] !== $to) {
  59050. throw new InvalidOptionsException(\sprintf(
  59051. 'Tag "%s" cannot be configured to be replaced with several different tags when case sensitivity is off.',
  59052. $from
  59053. ));
  59054. }
  59055. $from = $lowercaseFrom;
  59056. }
  59057. $normalizedValue[$from] = $to;
  59058. }
  59059. foreach ($normalizedValue as $from => $to) {
  59060. if (isset($normalizedValue[$to]) && $normalizedValue[$to] !== $to) {
  59061. throw new InvalidOptionsException(\sprintf(
  59062. 'Cannot change tag "%1$s" to tag "%2$s", as the tag "%2$s" is configured to be replaced to "%3$s".',
  59063. $from,
  59064. $to,
  59065. $normalizedValue[$to]
  59066. ));
  59067. }
  59068. }
  59069. return $normalizedValue;
  59070. })
  59071. ->setDefault([])
  59072. ->getOption(),
  59073. (new FixerOptionBuilder('case_sensitive', 'Whether tags should be replaced only if they have exact same casing.'))
  59074. ->setAllowedTypes(['bool'])
  59075. ->setDefault(false)
  59076. ->getOption(),
  59077. ]);
  59078. }
  59079. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59080. {
  59081. if (0 === \count($this->configuration['replacements'])) {
  59082. return;
  59083. }
  59084. if (true === $this->configuration['fix_annotation']) {
  59085. $regex = true === $this->configuration['fix_inline']
  59086. ? '/(["\'])[^\1]*\1(*SKIP)(*FAIL)|\b(?<=@)(?P<tag>%s)\b/'
  59087. : '/(["\'])[^\1]*\1(*SKIP)(*FAIL)|(?<!\{@)(?<=@)(?P<tag>%s)(?!\})/';
  59088. } else {
  59089. $regex = '/(?<={@)(?P<tag>%s)(?=[ \t}])/';
  59090. }
  59091. $caseInsensitive = false === $this->configuration['case_sensitive'];
  59092. $replacements = $this->configuration['replacements'];
  59093. $regex = \sprintf($regex, implode('|', array_keys($replacements)));
  59094. if ($caseInsensitive) {
  59095. $regex .= 'i';
  59096. }
  59097. foreach ($tokens as $index => $token) {
  59098. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59099. continue;
  59100. }
  59101. $tokens[$index] = new Token([T_DOC_COMMENT, Preg::replaceCallback(
  59102. $regex,
  59103. static function (array $matches) use ($caseInsensitive, $replacements) {
  59104. \assert(isset($matches['tag']));
  59105. if ($caseInsensitive) {
  59106. $matches['tag'] = strtolower($matches['tag']);
  59107. }
  59108. return $replacements[$matches['tag']];
  59109. },
  59110. $token->getContent()
  59111. )]);
  59112. }
  59113. }
  59114. }
  59115. <?php
  59116. declare(strict_types=1);
  59117. namespace PhpCsFixer\Fixer\Phpdoc;
  59118. use PhpCsFixer\AbstractFixer;
  59119. use PhpCsFixer\DocBlock\DocBlock;
  59120. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  59121. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  59122. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  59123. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  59124. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  59125. use PhpCsFixer\FixerDefinition\CodeSample;
  59126. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59127. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59128. use PhpCsFixer\Tokenizer\Token;
  59129. use PhpCsFixer\Tokenizer\Tokens;
  59130. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  59131. use PhpCsFixer\Utils;
  59132. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  59133. use Symfony\Component\OptionsResolver\Options;
  59134. /**
  59135. @phpstan-type
  59136. @phpstan-type
  59137. @implements
  59138. */
  59139. final class PhpdocReturnSelfReferenceFixer extends AbstractFixer implements ConfigurableFixerInterface
  59140. {
  59141. /**
  59142. @use */
  59143. use ConfigurableFixerTrait;
  59144. private const TO_TYPES = [
  59145. '$this',
  59146. 'static',
  59147. 'self',
  59148. ];
  59149. public function getDefinition(): FixerDefinitionInterface
  59150. {
  59151. return new FixerDefinition(
  59152. 'The type of `@return` annotations of methods returning a reference to itself must the configured one.',
  59153. [
  59154. new CodeSample(
  59155. '<?php
  59156. class Sample
  59157. {
  59158. /**
  59159. * @return this
  59160. */
  59161. public function test1()
  59162. {
  59163. return $this;
  59164. }
  59165. /**
  59166. * @return $self
  59167. */
  59168. public function test2()
  59169. {
  59170. return $this;
  59171. }
  59172. }
  59173. '
  59174. ),
  59175. new CodeSample(
  59176. '<?php
  59177. class Sample
  59178. {
  59179. /**
  59180. * @return this
  59181. */
  59182. public function test1()
  59183. {
  59184. return $this;
  59185. }
  59186. /**
  59187. * @return $self
  59188. */
  59189. public function test2()
  59190. {
  59191. return $this;
  59192. }
  59193. }
  59194. ',
  59195. ['replacements' => ['this' => 'self']]
  59196. ),
  59197. ]
  59198. );
  59199. }
  59200. public function isCandidate(Tokens $tokens): bool
  59201. {
  59202. return \count($tokens) > 10 && $tokens->isAllTokenKindsFound([T_DOC_COMMENT, T_FUNCTION]) && $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  59203. }
  59204. public function getPriority(): int
  59205. {
  59206. return 10;
  59207. }
  59208. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59209. {
  59210. $tokensAnalyzer = new TokensAnalyzer($tokens);
  59211. foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
  59212. if ('method' === $element['type']) {
  59213. $this->fixMethod($tokens, $index);
  59214. }
  59215. }
  59216. }
  59217. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  59218. {
  59219. $default = [
  59220. 'this' => '$this',
  59221. '@this' => '$this',
  59222. '$self' => 'self',
  59223. '@self' => 'self',
  59224. '$static' => 'static',
  59225. '@static' => 'static',
  59226. ];
  59227. return new FixerConfigurationResolver([
  59228. (new FixerOptionBuilder('replacements', 'Mapping between replaced return types with new ones.'))
  59229. ->setAllowedTypes(['array<string, string>'])
  59230. ->setNormalizer(static function (Options $options, array $value) use ($default): array {
  59231. $normalizedValue = [];
  59232. foreach ($value as $from => $to) {
  59233. if (\is_string($from)) {
  59234. $from = strtolower($from);
  59235. }
  59236. if (!isset($default[$from])) {
  59237. throw new InvalidOptionsException(\sprintf(
  59238. 'Unknown key "%s", expected any of %s.',
  59239. \gettype($from).'#'.$from,
  59240. Utils::naturalLanguageJoin(array_keys($default))
  59241. ));
  59242. }
  59243. if (!\in_array($to, self::TO_TYPES, true)) {
  59244. throw new InvalidOptionsException(\sprintf(
  59245. 'Unknown value "%s", expected any of %s.',
  59246. \is_object($to) ? \get_class($to) : \gettype($to).(\is_resource($to) ? '' : '#'.$to),
  59247. Utils::naturalLanguageJoin(self::TO_TYPES)
  59248. ));
  59249. }
  59250. $normalizedValue[$from] = $to;
  59251. }
  59252. return $normalizedValue;
  59253. })
  59254. ->setDefault($default)
  59255. ->getOption(),
  59256. ]);
  59257. }
  59258. private function fixMethod(Tokens $tokens, int $index): void
  59259. {
  59260. static $methodModifiers = [T_STATIC, T_FINAL, T_ABSTRACT, T_PRIVATE, T_PROTECTED, T_PUBLIC];
  59261. while (true) {
  59262. $tokenIndex = $tokens->getPrevMeaningfulToken($index);
  59263. if (!$tokens[$tokenIndex]->isGivenKind($methodModifiers)) {
  59264. break;
  59265. }
  59266. $index = $tokenIndex;
  59267. }
  59268. $docIndex = $tokens->getPrevNonWhitespace($index);
  59269. if (!$tokens[$docIndex]->isGivenKind(T_DOC_COMMENT)) {
  59270. return;
  59271. }
  59272. $docBlock = new DocBlock($tokens[$docIndex]->getContent());
  59273. $returnsBlock = $docBlock->getAnnotationsOfType('return');
  59274. if (0 === \count($returnsBlock)) {
  59275. return;
  59276. }
  59277. $returnsBlock = $returnsBlock[0];
  59278. $types = $returnsBlock->getTypes();
  59279. if (0 === \count($types)) {
  59280. return;
  59281. }
  59282. $newTypes = [];
  59283. foreach ($types as $type) {
  59284. $newTypes[] = $this->configuration['replacements'][strtolower($type)] ?? $type;
  59285. }
  59286. if ($types === $newTypes) {
  59287. return;
  59288. }
  59289. $returnsBlock->setTypes($newTypes);
  59290. $tokens[$docIndex] = new Token([T_DOC_COMMENT, $docBlock->getContent()]);
  59291. }
  59292. }
  59293. <?php
  59294. declare(strict_types=1);
  59295. namespace PhpCsFixer\Fixer\Phpdoc;
  59296. use PhpCsFixer\AbstractFixer;
  59297. use PhpCsFixer\DocBlock\DocBlock;
  59298. use PhpCsFixer\DocBlock\Line;
  59299. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  59300. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  59301. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  59302. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  59303. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  59304. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  59305. use PhpCsFixer\FixerDefinition\CodeSample;
  59306. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59307. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59308. use PhpCsFixer\Preg;
  59309. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  59310. use PhpCsFixer\Tokenizer\CT;
  59311. use PhpCsFixer\Tokenizer\FCT;
  59312. use PhpCsFixer\Tokenizer\Token;
  59313. use PhpCsFixer\Tokenizer\Tokens;
  59314. /**
  59315. @phpstan-type
  59316. @phpstan-type
  59317. @implements
  59318. */
  59319. final class PhpdocAddMissingParamAnnotationFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  59320. {
  59321. /**
  59322. @use */
  59323. use ConfigurableFixerTrait;
  59324. public function getDefinition(): FixerDefinitionInterface
  59325. {
  59326. return new FixerDefinition(
  59327. 'PHPDoc should contain `@param` for all params.',
  59328. [
  59329. new CodeSample(
  59330. '<?php
  59331. /**
  59332. * @param int $bar
  59333. *
  59334. * @return void
  59335. */
  59336. function f9(string $foo, $bar, $baz) {}
  59337. '
  59338. ),
  59339. new CodeSample(
  59340. '<?php
  59341. /**
  59342. * @param int $bar
  59343. *
  59344. * @return void
  59345. */
  59346. function f9(string $foo, $bar, $baz) {}
  59347. ',
  59348. ['only_untyped' => true]
  59349. ),
  59350. new CodeSample(
  59351. '<?php
  59352. /**
  59353. * @param int $bar
  59354. *
  59355. * @return void
  59356. */
  59357. function f9(string $foo, $bar, $baz) {}
  59358. ',
  59359. ['only_untyped' => false]
  59360. ),
  59361. ]
  59362. );
  59363. }
  59364. public function getPriority(): int
  59365. {
  59366. return 10;
  59367. }
  59368. public function isCandidate(Tokens $tokens): bool
  59369. {
  59370. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59371. }
  59372. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59373. {
  59374. $argumentsAnalyzer = new ArgumentsAnalyzer();
  59375. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  59376. $token = $tokens[$index];
  59377. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59378. continue;
  59379. }
  59380. $tokenContent = $token->getContent();
  59381. if (str_contains(strtolower($tokenContent), strtolower('inheritdoc'))) {
  59382. continue;
  59383. }
  59384. if (!str_contains($tokenContent, "\n")) {
  59385. continue;
  59386. }
  59387. $mainIndex = $index;
  59388. $index = $tokens->getNextMeaningfulToken($index);
  59389. if (null === $index) {
  59390. return;
  59391. }
  59392. while ($tokens[$index]->isGivenKind([
  59393. T_ABSTRACT,
  59394. T_FINAL,
  59395. T_PRIVATE,
  59396. T_PROTECTED,
  59397. T_PUBLIC,
  59398. T_STATIC,
  59399. ])) {
  59400. $index = $tokens->getNextMeaningfulToken($index);
  59401. }
  59402. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  59403. continue;
  59404. }
  59405. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  59406. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  59407. $arguments = [];
  59408. foreach ($argumentsAnalyzer->getArguments($tokens, $openIndex, $index) as $start => $end) {
  59409. $argumentInfo = $this->prepareArgumentInformation($tokens, $start, $end);
  59410. if (false === $this->configuration['only_untyped'] || '' === $argumentInfo['type']) {
  59411. $arguments[$argumentInfo['name']] = $argumentInfo;
  59412. }
  59413. }
  59414. if (0 === \count($arguments)) {
  59415. continue;
  59416. }
  59417. $doc = new DocBlock($tokenContent);
  59418. $lastParamLine = null;
  59419. foreach ($doc->getAnnotationsOfType('param') as $annotation) {
  59420. $pregMatched = Preg::match('/^[^$]+(\$\w+).*$/s', $annotation->getContent(), $matches);
  59421. if ($pregMatched) {
  59422. unset($arguments[$matches[1]]);
  59423. }
  59424. $lastParamLine = max($lastParamLine, $annotation->getEnd());
  59425. }
  59426. if (0 === \count($arguments)) {
  59427. continue;
  59428. }
  59429. $lines = $doc->getLines();
  59430. $linesCount = \count($lines);
  59431. Preg::match('/^(\s*).*$/', $lines[$linesCount - 1]->getContent(), $matches);
  59432. $indent = $matches[1];
  59433. $newLines = [];
  59434. foreach ($arguments as $argument) {
  59435. $type = '' !== $argument['type'] ? $argument['type'] : 'mixed';
  59436. if (!str_starts_with($type, '?') && 'null' === strtolower($argument['default'])) {
  59437. $type = 'null|'.$type;
  59438. }
  59439. $newLines[] = new Line(\sprintf(
  59440. '%s* @param %s %s%s',
  59441. $indent,
  59442. $type,
  59443. $argument['name'],
  59444. $this->whitespacesConfig->getLineEnding()
  59445. ));
  59446. }
  59447. array_splice(
  59448. $lines,
  59449. $lastParamLine > 0 ? $lastParamLine + 1 : $linesCount - 1,
  59450. 0,
  59451. $newLines
  59452. );
  59453. $tokens[$mainIndex] = new Token([T_DOC_COMMENT, implode('', $lines)]);
  59454. }
  59455. }
  59456. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  59457. {
  59458. return new FixerConfigurationResolver([
  59459. (new FixerOptionBuilder('only_untyped', 'Whether to add missing `@param` annotations for untyped parameters only.'))
  59460. ->setDefault(true)
  59461. ->setAllowedTypes(['bool'])
  59462. ->getOption(),
  59463. ]);
  59464. }
  59465. private function prepareArgumentInformation(Tokens $tokens, int $start, int $end): array
  59466. {
  59467. $info = [
  59468. 'default' => '',
  59469. 'name' => '',
  59470. 'type' => '',
  59471. ];
  59472. $sawName = false;
  59473. for ($index = $start; $index <= $end; ++$index) {
  59474. $token = $tokens[$index];
  59475. if (
  59476. $token->isComment()
  59477. || $token->isWhitespace()
  59478. || $token->isGivenKind([
  59479. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  59480. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  59481. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  59482. FCT::T_READONLY,
  59483. FCT::T_PRIVATE_SET,
  59484. FCT::T_PROTECTED_SET,
  59485. FCT::T_PUBLIC_SET,
  59486. ])
  59487. ) {
  59488. continue;
  59489. }
  59490. if ($token->isGivenKind(T_VARIABLE)) {
  59491. $sawName = true;
  59492. $info['name'] = $token->getContent();
  59493. continue;
  59494. }
  59495. if ($token->equals('=')) {
  59496. continue;
  59497. }
  59498. if ($sawName) {
  59499. $info['default'] .= $token->getContent();
  59500. } elseif (!$token->equals('&')) {
  59501. if ($token->isGivenKind(T_ELLIPSIS)) {
  59502. if ('' === $info['type']) {
  59503. $info['type'] = 'array';
  59504. } else {
  59505. $info['type'] .= '[]';
  59506. }
  59507. } else {
  59508. $info['type'] .= $token->getContent();
  59509. }
  59510. }
  59511. }
  59512. return $info;
  59513. }
  59514. }
  59515. <?php
  59516. declare(strict_types=1);
  59517. namespace PhpCsFixer\Fixer\Phpdoc;
  59518. use PhpCsFixer\AbstractFixer;
  59519. use PhpCsFixer\DocBlock\DocBlock;
  59520. use PhpCsFixer\DocBlock\Line;
  59521. use PhpCsFixer\DocBlock\ShortDescription;
  59522. use PhpCsFixer\FixerDefinition\CodeSample;
  59523. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59524. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59525. use PhpCsFixer\Tokenizer\Token;
  59526. use PhpCsFixer\Tokenizer\Tokens;
  59527. final class PhpdocTrimConsecutiveBlankLineSeparationFixer extends AbstractFixer
  59528. {
  59529. public function getDefinition(): FixerDefinitionInterface
  59530. {
  59531. return new FixerDefinition(
  59532. 'Removes extra blank lines after summary and after description in PHPDoc.',
  59533. [
  59534. new CodeSample(
  59535. '<?php
  59536. /**
  59537. * Summary.
  59538. *
  59539. *
  59540. * Description that contain 4 lines,
  59541. *
  59542. *
  59543. * while 2 of them are blank!
  59544. *
  59545. *
  59546. * @param string $foo
  59547. *
  59548. *
  59549. * @dataProvider provideFixCases
  59550. */
  59551. function fnc($foo) {}
  59552. '
  59553. ),
  59554. ]
  59555. );
  59556. }
  59557. public function getPriority(): int
  59558. {
  59559. return -41;
  59560. }
  59561. public function isCandidate(Tokens $tokens): bool
  59562. {
  59563. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59564. }
  59565. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59566. {
  59567. foreach ($tokens as $index => $token) {
  59568. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59569. continue;
  59570. }
  59571. $doc = new DocBlock($token->getContent());
  59572. $summaryEnd = (new ShortDescription($doc))->getEnd();
  59573. if (null !== $summaryEnd) {
  59574. $this->fixSummary($doc, $summaryEnd);
  59575. $this->fixDescription($doc, $summaryEnd);
  59576. }
  59577. $this->fixAllTheRest($doc);
  59578. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  59579. }
  59580. }
  59581. private function fixSummary(DocBlock $doc, int $summaryEnd): void
  59582. {
  59583. $nonBlankLineAfterSummary = $this->findNonBlankLine($doc, $summaryEnd);
  59584. $this->removeExtraBlankLinesBetween($doc, $summaryEnd, $nonBlankLineAfterSummary);
  59585. }
  59586. private function fixDescription(DocBlock $doc, int $summaryEnd): void
  59587. {
  59588. $annotationStart = $this->findFirstAnnotationOrEnd($doc);
  59589. $descriptionEnd = $this->reverseFindLastUsefulContent($doc, $annotationStart);
  59590. if (null === $descriptionEnd || $summaryEnd === $descriptionEnd) {
  59591. return;
  59592. }
  59593. if ($annotationStart === \count($doc->getLines()) - 1) {
  59594. return;
  59595. }
  59596. $this->removeExtraBlankLinesBetween($doc, $descriptionEnd, $annotationStart);
  59597. }
  59598. private function fixAllTheRest(DocBlock $doc): void
  59599. {
  59600. $annotationStart = $this->findFirstAnnotationOrEnd($doc);
  59601. $lastLine = $this->reverseFindLastUsefulContent($doc, \count($doc->getLines()) - 1);
  59602. if (null !== $lastLine && $annotationStart !== $lastLine) {
  59603. $this->removeExtraBlankLinesBetween($doc, $annotationStart, $lastLine);
  59604. }
  59605. }
  59606. private function removeExtraBlankLinesBetween(DocBlock $doc, int $from, int $to): void
  59607. {
  59608. for ($index = $from + 1; $index < $to; ++$index) {
  59609. $line = $doc->getLine($index);
  59610. $next = $doc->getLine($index + 1);
  59611. $this->removeExtraBlankLine($line, $next);
  59612. }
  59613. }
  59614. private function removeExtraBlankLine(Line $current, Line $next): void
  59615. {
  59616. if (!$current->isTheEnd() && !$current->containsUsefulContent()
  59617. && !$next->isTheEnd() && !$next->containsUsefulContent()) {
  59618. $current->remove();
  59619. }
  59620. }
  59621. private function findNonBlankLine(DocBlock $doc, int $after): ?int
  59622. {
  59623. foreach ($doc->getLines() as $index => $line) {
  59624. if ($index <= $after) {
  59625. continue;
  59626. }
  59627. if ($line->containsATag() || $line->containsUsefulContent() || $line->isTheEnd()) {
  59628. return $index;
  59629. }
  59630. }
  59631. return null;
  59632. }
  59633. private function findFirstAnnotationOrEnd(DocBlock $doc): int
  59634. {
  59635. foreach ($doc->getLines() as $index => $line) {
  59636. if ($line->containsATag()) {
  59637. return $index;
  59638. }
  59639. }
  59640. if (!isset($index)) {
  59641. throw new \LogicException('PHPDoc has empty lines collection.');
  59642. }
  59643. return $index;
  59644. }
  59645. private function reverseFindLastUsefulContent(DocBlock $doc, int $from): ?int
  59646. {
  59647. for ($index = $from - 1; $index >= 0; --$index) {
  59648. if ($doc->getLine($index)->containsUsefulContent()) {
  59649. return $index;
  59650. }
  59651. }
  59652. return null;
  59653. }
  59654. }
  59655. <?php
  59656. declare(strict_types=1);
  59657. namespace PhpCsFixer\Fixer\Phpdoc;
  59658. use PhpCsFixer\AbstractFixer;
  59659. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  59660. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  59661. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  59662. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  59663. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  59664. use PhpCsFixer\FixerDefinition\CodeSample;
  59665. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59666. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59667. use PhpCsFixer\Preg;
  59668. use PhpCsFixer\Tokenizer\Token;
  59669. use PhpCsFixer\Tokenizer\Tokens;
  59670. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  59671. use Symfony\Component\OptionsResolver\Options;
  59672. /**
  59673. @phpstan-type
  59674. @phpstan-type
  59675. @implements
  59676. */
  59677. final class PhpdocTagTypeFixer extends AbstractFixer implements ConfigurableFixerInterface
  59678. {
  59679. /**
  59680. @use */
  59681. use ConfigurableFixerTrait;
  59682. private const TAG_REGEX = '/^(?:
  59683. (?<tag>
  59684. (?:@(?<tag_name>.+?)(?:\s.+)?)
  59685. )
  59686. |
  59687. {(?<inlined_tag>
  59688. (?:@(?<inlined_tag_name>.+?)(?:\s.+)?)
  59689. )}
  59690. )$/x';
  59691. public function isCandidate(Tokens $tokens): bool
  59692. {
  59693. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59694. }
  59695. public function getDefinition(): FixerDefinitionInterface
  59696. {
  59697. return new FixerDefinition(
  59698. 'Forces PHPDoc tags to be either regular annotations or inline.',
  59699. [
  59700. new CodeSample(
  59701. "<?php\n/**\n * {@api}\n */\n"
  59702. ),
  59703. new CodeSample(
  59704. "<?php\n/**\n * @inheritdoc\n */\n",
  59705. ['tags' => ['inheritdoc' => 'inline']]
  59706. ),
  59707. ]
  59708. );
  59709. }
  59710. public function getPriority(): int
  59711. {
  59712. return 0;
  59713. }
  59714. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59715. {
  59716. if (0 === \count($this->configuration['tags'])) {
  59717. return;
  59718. }
  59719. $regularExpression = \sprintf(
  59720. '/({?@(?:%s).*?(?:(?=\s\*\/)|(?=\n)}?))/i',
  59721. implode('|', array_map(
  59722. static fn (string $tag): string => preg_quote($tag, '/'),
  59723. array_keys($this->configuration['tags'])
  59724. ))
  59725. );
  59726. foreach ($tokens as $index => $token) {
  59727. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59728. continue;
  59729. }
  59730. $parts = Preg::split(
  59731. $regularExpression,
  59732. $token->getContent(),
  59733. -1,
  59734. PREG_SPLIT_DELIM_CAPTURE
  59735. );
  59736. for ($i = 1, $max = \count($parts) - 1; $i < $max; $i += 2) {
  59737. if (!Preg::match(self::TAG_REGEX, $parts[$i], $matches)) {
  59738. continue;
  59739. }
  59740. if ('' !== $matches['tag']) {
  59741. $tag = $matches['tag'];
  59742. $tagName = $matches['tag_name'];
  59743. } else {
  59744. $tag = $matches['inlined_tag'];
  59745. $tagName = $matches['inlined_tag_name'];
  59746. }
  59747. $tagName = strtolower($tagName);
  59748. if (!isset($this->configuration['tags'][$tagName])) {
  59749. continue;
  59750. }
  59751. if ('inline' === $this->configuration['tags'][$tagName]) {
  59752. $parts[$i] = '{'.$tag.'}';
  59753. continue;
  59754. }
  59755. if (!$this->tagIsSurroundedByText($parts, $i)) {
  59756. $parts[$i] = $tag;
  59757. }
  59758. }
  59759. $tokens[$index] = new Token([T_DOC_COMMENT, implode('', $parts)]);
  59760. }
  59761. }
  59762. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  59763. {
  59764. return new FixerConfigurationResolver([
  59765. (new FixerOptionBuilder('tags', 'The list of tags to fix.'))
  59766. ->setAllowedTypes(["array<string, 'annotation'|'inline'>"])
  59767. ->setAllowedValues([static function (array $value): bool {
  59768. foreach ($value as $type) {
  59769. if (!\in_array($type, ['annotation', 'inline'], true)) {
  59770. throw new InvalidOptionsException("Unknown tag type \"{$type}\".");
  59771. }
  59772. }
  59773. return true;
  59774. }])
  59775. ->setDefault([
  59776. 'api' => 'annotation',
  59777. 'author' => 'annotation',
  59778. 'copyright' => 'annotation',
  59779. 'deprecated' => 'annotation',
  59780. 'example' => 'annotation',
  59781. 'global' => 'annotation',
  59782. 'inheritDoc' => 'annotation',
  59783. 'internal' => 'annotation',
  59784. 'license' => 'annotation',
  59785. 'method' => 'annotation',
  59786. 'package' => 'annotation',
  59787. 'param' => 'annotation',
  59788. 'property' => 'annotation',
  59789. 'return' => 'annotation',
  59790. 'see' => 'annotation',
  59791. 'since' => 'annotation',
  59792. 'throws' => 'annotation',
  59793. 'todo' => 'annotation',
  59794. 'uses' => 'annotation',
  59795. 'var' => 'annotation',
  59796. 'version' => 'annotation',
  59797. ])
  59798. ->setNormalizer(static function (Options $options, array $value): array {
  59799. $normalized = [];
  59800. foreach ($value as $tag => $type) {
  59801. $normalized[strtolower($tag)] = $type;
  59802. }
  59803. return $normalized;
  59804. })
  59805. ->getOption(),
  59806. ]);
  59807. }
  59808. private function tagIsSurroundedByText(array $parts, int $index): bool
  59809. {
  59810. return
  59811. Preg::match('/(^|\R)\h*[^@\s]\N*/', $this->cleanComment($parts[$index - 1]))
  59812. || Preg::match('/^.*?\R\s*[^@\s]/', $this->cleanComment($parts[$index + 1]));
  59813. }
  59814. private function cleanComment(string $comment): string
  59815. {
  59816. $comment = Preg::replace('/^\/\*\*|\*\/$/', '', $comment);
  59817. return Preg::replace('/(\R)(\h*\*)?\h*/', '$1', $comment);
  59818. }
  59819. }
  59820. <?php
  59821. declare(strict_types=1);
  59822. namespace PhpCsFixer\Fixer\Phpdoc;
  59823. use PhpCsFixer\AbstractFixer;
  59824. use PhpCsFixer\DocBlock\DocBlock;
  59825. use PhpCsFixer\DocBlock\ShortDescription;
  59826. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  59827. use PhpCsFixer\FixerDefinition\CodeSample;
  59828. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59829. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59830. use PhpCsFixer\Tokenizer\Token;
  59831. use PhpCsFixer\Tokenizer\Tokens;
  59832. final class PhpdocSummaryFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  59833. {
  59834. public function getDefinition(): FixerDefinitionInterface
  59835. {
  59836. return new FixerDefinition(
  59837. 'PHPDoc summary should end in either a full stop, exclamation mark, or question mark.',
  59838. [new CodeSample('<?php
  59839. /**
  59840. * Foo function is great
  59841. */
  59842. function foo () {}
  59843. ')]
  59844. );
  59845. }
  59846. public function getPriority(): int
  59847. {
  59848. return 0;
  59849. }
  59850. public function isCandidate(Tokens $tokens): bool
  59851. {
  59852. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59853. }
  59854. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59855. {
  59856. foreach ($tokens as $index => $token) {
  59857. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59858. continue;
  59859. }
  59860. $doc = new DocBlock($token->getContent());
  59861. $end = (new ShortDescription($doc))->getEnd();
  59862. if (null !== $end) {
  59863. $line = $doc->getLine($end);
  59864. $content = rtrim($line->getContent());
  59865. if (
  59866. !$this->isCorrectlyFormatted($content)
  59867. && (1 === $end || ($doc->isMultiLine() && ':' !== substr(rtrim($doc->getLine(1)->getContent()), -1)))
  59868. ) {
  59869. $line->setContent($content.'.'.$this->whitespacesConfig->getLineEnding());
  59870. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  59871. }
  59872. }
  59873. }
  59874. }
  59875. private function isCorrectlyFormatted(string $content): bool
  59876. {
  59877. if (str_contains(strtolower($content), strtolower('{@inheritdoc}'))) {
  59878. return true;
  59879. }
  59880. return $content !== rtrim($content, '.:。!?¡¿�?');
  59881. }
  59882. }
  59883. <?php
  59884. declare(strict_types=1);
  59885. namespace PhpCsFixer\Fixer\Phpdoc;
  59886. use PhpCsFixer\AbstractProxyFixer;
  59887. use PhpCsFixer\FixerDefinition\CodeSample;
  59888. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59889. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59890. final class PhpdocNoPackageFixer extends AbstractProxyFixer
  59891. {
  59892. public function getDefinition(): FixerDefinitionInterface
  59893. {
  59894. return new FixerDefinition(
  59895. '`@package` and `@subpackage` annotations must be removed from PHPDoc.',
  59896. [
  59897. new CodeSample(
  59898. '<?php
  59899. /**
  59900. * @internal
  59901. * @package Foo
  59902. * subpackage Bar
  59903. */
  59904. class Baz
  59905. {
  59906. }
  59907. '
  59908. ),
  59909. ]
  59910. );
  59911. }
  59912. public function getPriority(): int
  59913. {
  59914. return parent::getPriority();
  59915. }
  59916. protected function createProxyFixers(): array
  59917. {
  59918. $fixer = new GeneralPhpdocAnnotationRemoveFixer();
  59919. $fixer->configure([
  59920. 'annotations' => ['package', 'subpackage'],
  59921. 'case_sensitive' => true,
  59922. ]);
  59923. return [$fixer];
  59924. }
  59925. }
  59926. <?php
  59927. declare(strict_types=1);
  59928. namespace PhpCsFixer\Fixer\Phpdoc;
  59929. use PhpCsFixer\AbstractFixer;
  59930. use PhpCsFixer\FixerDefinition\CodeSample;
  59931. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59932. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59933. use PhpCsFixer\Preg;
  59934. use PhpCsFixer\Tokenizer\Token;
  59935. use PhpCsFixer\Tokenizer\Tokens;
  59936. final class NoEmptyPhpdocFixer extends AbstractFixer
  59937. {
  59938. public function getDefinition(): FixerDefinitionInterface
  59939. {
  59940. return new FixerDefinition(
  59941. 'There should not be empty PHPDoc blocks.',
  59942. [new CodeSample("<?php /** */\n")]
  59943. );
  59944. }
  59945. public function getPriority(): int
  59946. {
  59947. return 3;
  59948. }
  59949. public function isCandidate(Tokens $tokens): bool
  59950. {
  59951. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  59952. }
  59953. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  59954. {
  59955. foreach ($tokens as $index => $token) {
  59956. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  59957. continue;
  59958. }
  59959. if (!Preg::match('#^/\*\*[\s\*]*\*/$#', $token->getContent())) {
  59960. continue;
  59961. }
  59962. if (
  59963. $tokens[$index - 1]->isGivenKind([T_OPEN_TAG, T_WHITESPACE])
  59964. && substr_count($tokens[$index - 1]->getContent(), "\n") > 0
  59965. && $tokens[$index + 1]->isGivenKind(T_WHITESPACE)
  59966. && Preg::match('/^\R/', $tokens[$index + 1]->getContent())
  59967. ) {
  59968. $tokens[$index - 1] = new Token([
  59969. $tokens[$index - 1]->getId(),
  59970. Preg::replace('/\h*$/', '', $tokens[$index - 1]->getContent()),
  59971. ]);
  59972. $newContent = Preg::replace('/^\R/', '', $tokens[$index + 1]->getContent());
  59973. if ('' === $newContent) {
  59974. $tokens->clearAt($index + 1);
  59975. } else {
  59976. $tokens[$index + 1] = new Token([T_WHITESPACE, $newContent]);
  59977. }
  59978. }
  59979. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  59980. }
  59981. }
  59982. }
  59983. <?php
  59984. declare(strict_types=1);
  59985. namespace PhpCsFixer\Fixer\Phpdoc;
  59986. use PhpCsFixer\AbstractProxyFixer;
  59987. use PhpCsFixer\FixerDefinition\CodeSample;
  59988. use PhpCsFixer\FixerDefinition\FixerDefinition;
  59989. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  59990. final class PhpdocNoAccessFixer extends AbstractProxyFixer
  59991. {
  59992. public function getDefinition(): FixerDefinitionInterface
  59993. {
  59994. return new FixerDefinition(
  59995. '`@access` annotations must be removed from PHPDoc.',
  59996. [
  59997. new CodeSample(
  59998. '<?php
  59999. class Foo
  60000. {
  60001. /**
  60002. * @internal
  60003. * @access private
  60004. */
  60005. private $bar;
  60006. }
  60007. '
  60008. ),
  60009. ]
  60010. );
  60011. }
  60012. public function getPriority(): int
  60013. {
  60014. return parent::getPriority();
  60015. }
  60016. protected function createProxyFixers(): array
  60017. {
  60018. $fixer = new GeneralPhpdocAnnotationRemoveFixer();
  60019. $fixer->configure(
  60020. ['annotations' => ['access'],
  60021. 'case_sensitive' => true,
  60022. ]
  60023. );
  60024. return [$fixer];
  60025. }
  60026. }
  60027. <?php
  60028. declare(strict_types=1);
  60029. namespace PhpCsFixer\Fixer\Phpdoc;
  60030. use PhpCsFixer\AbstractPhpdocTypesFixer;
  60031. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60032. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60033. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  60034. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60035. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60036. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60037. use PhpCsFixer\FixerDefinition\CodeSample;
  60038. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60039. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60040. /**
  60041. @phpstan-type
  60042. @phpstan-type
  60043. @implements
  60044. */
  60045. final class PhpdocScalarFixer extends AbstractPhpdocTypesFixer implements ConfigurableFixerInterface
  60046. {
  60047. /**
  60048. @use */
  60049. use ConfigurableFixerTrait;
  60050. private const TYPES_MAP = [
  60051. 'boolean' => 'bool',
  60052. 'callback' => 'callable',
  60053. 'double' => 'float',
  60054. 'integer' => 'int',
  60055. 'real' => 'float',
  60056. 'str' => 'string',
  60057. ];
  60058. public function getDefinition(): FixerDefinitionInterface
  60059. {
  60060. return new FixerDefinition(
  60061. 'Scalar types should always be written in the same form. `int` not `integer`, `bool` not `boolean`, `float` not `real` or `double`.',
  60062. [
  60063. new CodeSample('<?php
  60064. /**
  60065. * @param integer $a
  60066. * @param boolean $b
  60067. * @param real $c
  60068. *
  60069. * @return double
  60070. */
  60071. function sample($a, $b, $c)
  60072. {
  60073. return sample2($a, $b, $c);
  60074. }
  60075. '),
  60076. new CodeSample(
  60077. '<?php
  60078. /**
  60079. * @param integer $a
  60080. * @param boolean $b
  60081. * @param real $c
  60082. */
  60083. function sample($a, $b, $c)
  60084. {
  60085. return sample2($a, $b, $c);
  60086. }
  60087. ',
  60088. ['types' => ['boolean']]
  60089. ),
  60090. ]
  60091. );
  60092. }
  60093. public function getPriority(): int
  60094. {
  60095. return 15;
  60096. }
  60097. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60098. {
  60099. $types = array_keys(self::TYPES_MAP);
  60100. return new FixerConfigurationResolver([
  60101. (new FixerOptionBuilder('types', 'A list of types to fix.'))
  60102. ->setAllowedValues([new AllowedValueSubset($types)])
  60103. ->setDefault($types)
  60104. ->getOption(),
  60105. ]);
  60106. }
  60107. protected function normalize(string $type): string
  60108. {
  60109. $suffix = '';
  60110. while (str_ends_with($type, '[]')) {
  60111. $type = substr($type, 0, -2);
  60112. $suffix .= '[]';
  60113. }
  60114. if (\in_array($type, $this->configuration['types'], true)) {
  60115. $type = self::TYPES_MAP[$type];
  60116. }
  60117. return $type.$suffix;
  60118. }
  60119. }
  60120. <?php
  60121. declare(strict_types=1);
  60122. namespace PhpCsFixer\Fixer\Phpdoc;
  60123. use PhpCsFixer\AbstractFixer;
  60124. use PhpCsFixer\DocBlock\Annotation;
  60125. use PhpCsFixer\DocBlock\DocBlock;
  60126. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60127. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60128. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60129. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60130. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60131. use PhpCsFixer\FixerDefinition\CodeSample;
  60132. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60133. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60134. use PhpCsFixer\Tokenizer\Token;
  60135. use PhpCsFixer\Tokenizer\Tokens;
  60136. /**
  60137. @phpstan-type
  60138. @phpstan-type
  60139. @implements
  60140. */
  60141. final class GeneralPhpdocAnnotationRemoveFixer extends AbstractFixer implements ConfigurableFixerInterface
  60142. {
  60143. /**
  60144. @use */
  60145. use ConfigurableFixerTrait;
  60146. public function getDefinition(): FixerDefinitionInterface
  60147. {
  60148. return new FixerDefinition(
  60149. 'Removes configured annotations from PHPDoc.',
  60150. [
  60151. new CodeSample(
  60152. '<?php
  60153. /**
  60154. * @internal
  60155. * @author John Doe
  60156. * @AuThOr Jane Doe
  60157. */
  60158. function foo() {}
  60159. ',
  60160. ['annotations' => ['author']]
  60161. ),
  60162. new CodeSample(
  60163. '<?php
  60164. /**
  60165. * @internal
  60166. * @author John Doe
  60167. * @AuThOr Jane Doe
  60168. */
  60169. function foo() {}
  60170. ',
  60171. ['annotations' => ['author'], 'case_sensitive' => false]
  60172. ),
  60173. new CodeSample(
  60174. '<?php
  60175. /**
  60176. * @author John Doe
  60177. * @package ACME API
  60178. * @subpackage Authorization
  60179. * @version 1.0
  60180. */
  60181. function foo() {}
  60182. ',
  60183. ['annotations' => ['package', 'subpackage']]
  60184. ),
  60185. ]
  60186. );
  60187. }
  60188. public function getPriority(): int
  60189. {
  60190. return 10;
  60191. }
  60192. public function isCandidate(Tokens $tokens): bool
  60193. {
  60194. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  60195. }
  60196. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60197. {
  60198. if (0 === \count($this->configuration['annotations'])) {
  60199. return;
  60200. }
  60201. foreach ($tokens as $index => $token) {
  60202. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  60203. continue;
  60204. }
  60205. $doc = new DocBlock($token->getContent());
  60206. $annotations = $this->getAnnotationsToRemove($doc);
  60207. if (0 === \count($annotations)) {
  60208. continue;
  60209. }
  60210. foreach ($annotations as $annotation) {
  60211. $annotation->remove();
  60212. }
  60213. if ('' === $doc->getContent()) {
  60214. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  60215. } else {
  60216. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  60217. }
  60218. }
  60219. }
  60220. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60221. {
  60222. return new FixerConfigurationResolver([
  60223. (new FixerOptionBuilder('annotations', 'List of annotations to remove, e.g. `["author"]`.'))
  60224. ->setAllowedTypes(['string[]'])
  60225. ->setDefault([])
  60226. ->getOption(),
  60227. (new FixerOptionBuilder('case_sensitive', 'Should annotations be case sensitive.'))
  60228. ->setAllowedTypes(['bool'])
  60229. ->setDefault(true)
  60230. ->getOption(),
  60231. ]);
  60232. }
  60233. private function getAnnotationsToRemove(DocBlock $doc): array
  60234. {
  60235. if (true === $this->configuration['case_sensitive']) {
  60236. return $doc->getAnnotationsOfType($this->configuration['annotations']);
  60237. }
  60238. $typesToSearchFor = array_map(static fn (string $type): string => strtolower($type), $this->configuration['annotations']);
  60239. $annotations = [];
  60240. foreach ($doc->getAnnotations() as $annotation) {
  60241. $tagName = strtolower($annotation->getTag()->getName());
  60242. if (\in_array($tagName, $typesToSearchFor, true)) {
  60243. $annotations[] = $annotation;
  60244. }
  60245. }
  60246. return $annotations;
  60247. }
  60248. }
  60249. <?php
  60250. declare(strict_types=1);
  60251. namespace PhpCsFixer\Fixer\Phpdoc;
  60252. use PhpCsFixer\AbstractFixer;
  60253. use PhpCsFixer\DocBlock\DocBlock;
  60254. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60255. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60256. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  60257. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60258. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60259. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60260. use PhpCsFixer\FixerDefinition\CodeSample;
  60261. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60262. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60263. use PhpCsFixer\Preg;
  60264. use PhpCsFixer\Tokenizer\Token;
  60265. use PhpCsFixer\Tokenizer\Tokens;
  60266. use Symfony\Component\OptionsResolver\Options;
  60267. /**
  60268. @phpstan-type
  60269. @phpstan-type
  60270. @implements
  60271. */
  60272. final class PhpdocOrderByValueFixer extends AbstractFixer implements ConfigurableFixerInterface
  60273. {
  60274. /**
  60275. @use */
  60276. use ConfigurableFixerTrait;
  60277. public function getDefinition(): FixerDefinitionInterface
  60278. {
  60279. return new FixerDefinition(
  60280. 'Order PHPDoc tags by value.',
  60281. [
  60282. new CodeSample(
  60283. '<?php
  60284. /**
  60285. * @covers Foo
  60286. * @covers Bar
  60287. */
  60288. final class MyTest extends \PHPUnit_Framework_TestCase
  60289. {}
  60290. '
  60291. ),
  60292. new CodeSample(
  60293. '<?php
  60294. /**
  60295. * @author Bob
  60296. * @author Alice
  60297. */
  60298. final class MyTest extends \PHPUnit_Framework_TestCase
  60299. {}
  60300. ',
  60301. [
  60302. 'annotations' => [
  60303. 'author',
  60304. ],
  60305. ]
  60306. ),
  60307. ]
  60308. );
  60309. }
  60310. public function getPriority(): int
  60311. {
  60312. return -10;
  60313. }
  60314. public function isCandidate(Tokens $tokens): bool
  60315. {
  60316. return $tokens->isAllTokenKindsFound([T_CLASS, T_DOC_COMMENT]);
  60317. }
  60318. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60319. {
  60320. if ([] === $this->configuration['annotations']) {
  60321. return;
  60322. }
  60323. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  60324. foreach ($this->configuration['annotations'] as $type => $typeLowerCase) {
  60325. $findPattern = \sprintf(
  60326. '/@%s\s.+@%s\s/s',
  60327. $type,
  60328. $type
  60329. );
  60330. if (
  60331. !$tokens[$index]->isGivenKind(T_DOC_COMMENT)
  60332. || !Preg::match($findPattern, $tokens[$index]->getContent())
  60333. ) {
  60334. continue;
  60335. }
  60336. $docBlock = new DocBlock($tokens[$index]->getContent());
  60337. $annotations = $docBlock->getAnnotationsOfType($type);
  60338. $annotationMap = [];
  60339. if (\in_array($type, ['property', 'property-read', 'property-write'], true)) {
  60340. $replacePattern = \sprintf(
  60341. '/(?s)\*\s*@%s\s+(?P<optionalTypes>.+\s+)?\$(?P<comparableContent>\S+).*/',
  60342. $type
  60343. );
  60344. $replacement = '\2';
  60345. } elseif ('method' === $type) {
  60346. $replacePattern = '/(?s)\*\s*@method\s+(?P<optionalReturnTypes>.+\s+)?(?P<comparableContent>.+)\(.*/';
  60347. $replacement = '\2';
  60348. } else {
  60349. $replacePattern = \sprintf(
  60350. '/\*\s*@%s\s+(?P<comparableContent>.+)/',
  60351. $typeLowerCase
  60352. );
  60353. $replacement = '\1';
  60354. }
  60355. foreach ($annotations as $annotation) {
  60356. $rawContent = $annotation->getContent();
  60357. $comparableContent = Preg::replace(
  60358. $replacePattern,
  60359. $replacement,
  60360. strtolower(trim($rawContent))
  60361. );
  60362. $annotationMap[$comparableContent] = $rawContent;
  60363. }
  60364. $orderedAnnotationMap = $annotationMap;
  60365. ksort($orderedAnnotationMap, SORT_STRING);
  60366. if ($orderedAnnotationMap === $annotationMap) {
  60367. continue;
  60368. }
  60369. $lines = $docBlock->getLines();
  60370. foreach (array_reverse($annotations) as $annotation) {
  60371. array_splice(
  60372. $lines,
  60373. $annotation->getStart(),
  60374. $annotation->getEnd() - $annotation->getStart() + 1,
  60375. array_pop($orderedAnnotationMap)
  60376. );
  60377. }
  60378. $tokens[$index] = new Token([T_DOC_COMMENT, implode('', $lines)]);
  60379. }
  60380. }
  60381. }
  60382. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60383. {
  60384. $allowedValues = [
  60385. 'author',
  60386. 'covers',
  60387. 'coversNothing',
  60388. 'dataProvider',
  60389. 'depends',
  60390. 'group',
  60391. 'internal',
  60392. 'method',
  60393. 'mixin',
  60394. 'property',
  60395. 'property-read',
  60396. 'property-write',
  60397. 'requires',
  60398. 'throws',
  60399. 'uses',
  60400. ];
  60401. return new FixerConfigurationResolver([
  60402. (new FixerOptionBuilder('annotations', 'List of annotations to order, e.g. `["covers"]`.'))
  60403. ->setAllowedTypes(['string[]'])
  60404. ->setAllowedValues([
  60405. new AllowedValueSubset($allowedValues),
  60406. ])
  60407. ->setNormalizer(static function (Options $options, array $value): array {
  60408. $normalized = [];
  60409. foreach ($value as $annotation) {
  60410. $normalized[$annotation] = strtolower($annotation);
  60411. }
  60412. return $normalized;
  60413. })
  60414. ->setDefault([
  60415. 'covers',
  60416. ])
  60417. ->getOption(),
  60418. ]);
  60419. }
  60420. }
  60421. <?php
  60422. declare(strict_types=1);
  60423. namespace PhpCsFixer\Fixer\Phpdoc;
  60424. use PhpCsFixer\AbstractFixer;
  60425. use PhpCsFixer\DocBlock\Annotation;
  60426. use PhpCsFixer\DocBlock\DocBlock;
  60427. use PhpCsFixer\DocBlock\TypeExpression;
  60428. use PhpCsFixer\FixerDefinition\CodeSample;
  60429. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60430. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60431. use PhpCsFixer\Preg;
  60432. use PhpCsFixer\Tokenizer\Token;
  60433. use PhpCsFixer\Tokenizer\Tokens;
  60434. final class PhpdocParamOrderFixer extends AbstractFixer
  60435. {
  60436. private const PARAM_TAG = 'param';
  60437. public function isCandidate(Tokens $tokens): bool
  60438. {
  60439. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  60440. }
  60441. public function getPriority(): int
  60442. {
  60443. return parent::getPriority();
  60444. }
  60445. public function getDefinition(): FixerDefinitionInterface
  60446. {
  60447. return new FixerDefinition(
  60448. 'Orders all `@param` annotations in DocBlocks according to method signature.',
  60449. [
  60450. new CodeSample(
  60451. '<?php
  60452. /**
  60453. * Annotations in wrong order
  60454. *
  60455. * @param int $a
  60456. * @param Foo $c
  60457. * @param array $b
  60458. */
  60459. function m($a, array $b, Foo $c) {}
  60460. '
  60461. ),
  60462. ]
  60463. );
  60464. }
  60465. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60466. {
  60467. foreach ($tokens as $index => $token) {
  60468. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  60469. continue;
  60470. }
  60471. $nextFunctionToken = $tokens->getNextTokenOfKind($index, [[T_FUNCTION], [T_FN]]);
  60472. if (null === $nextFunctionToken) {
  60473. return;
  60474. }
  60475. $paramBlockStart = $tokens->getNextTokenOfKind($index, ['(']);
  60476. if (null === $paramBlockStart) {
  60477. return;
  60478. }
  60479. $doc = new DocBlock($token->getContent());
  60480. $paramAnnotations = $doc->getAnnotationsOfType(self::PARAM_TAG);
  60481. if ([] === $paramAnnotations) {
  60482. continue;
  60483. }
  60484. $paramNames = $this->getFunctionParamNames($tokens, $paramBlockStart);
  60485. $doc = $this->rewriteDocBlock($doc, $paramNames, $paramAnnotations);
  60486. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  60487. }
  60488. }
  60489. private function getFunctionParamNames(Tokens $tokens, int $paramBlockStart): array
  60490. {
  60491. $paramBlockEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $paramBlockStart);
  60492. $paramNames = [];
  60493. for (
  60494. $i = $tokens->getNextTokenOfKind($paramBlockStart, [[T_VARIABLE]]);
  60495. null !== $i && $i < $paramBlockEnd;
  60496. $i = $tokens->getNextTokenOfKind($i, [[T_VARIABLE]])
  60497. ) {
  60498. $paramNames[] = $tokens[$i];
  60499. }
  60500. return $paramNames;
  60501. }
  60502. private function rewriteDocBlock(DocBlock $doc, array $paramNames, array $paramAnnotations): DocBlock
  60503. {
  60504. $orderedAnnotations = $this->sortParamAnnotations($paramNames, $paramAnnotations);
  60505. $otherAnnotations = $this->getOtherAnnotationsBetweenParams($doc, $paramAnnotations);
  60506. if ([] !== $otherAnnotations) {
  60507. array_push($orderedAnnotations, ...$otherAnnotations);
  60508. }
  60509. $paramsStart = reset($paramAnnotations)->getStart();
  60510. $paramsEnd = end($paramAnnotations)->getEnd();
  60511. foreach ($doc->getAnnotations() as $annotation) {
  60512. if ($annotation->getStart() < $paramsStart || $annotation->getEnd() > $paramsEnd) {
  60513. continue;
  60514. }
  60515. $annotation->remove();
  60516. $doc
  60517. ->getLine($annotation->getStart())
  60518. ->setContent(current($orderedAnnotations))
  60519. ;
  60520. next($orderedAnnotations);
  60521. }
  60522. return $doc;
  60523. }
  60524. private function sortParamAnnotations(array $funcParamNames, array $paramAnnotations): array
  60525. {
  60526. $validParams = [];
  60527. foreach ($funcParamNames as $paramName) {
  60528. $indices = $this->findParamAnnotationByIdentifier($paramAnnotations, $paramName->getContent());
  60529. if (\is_array($indices)) {
  60530. foreach ($indices as $index) {
  60531. $validParams[$index] = $paramAnnotations[$index]->getContent();
  60532. }
  60533. }
  60534. }
  60535. $invalidParams = array_values(
  60536. array_diff_key($paramAnnotations, $validParams)
  60537. );
  60538. $orderedParams = array_values($validParams);
  60539. foreach ($invalidParams as $params) {
  60540. $orderedParams[] = $params->getContent();
  60541. }
  60542. return $orderedParams;
  60543. }
  60544. private function getOtherAnnotationsBetweenParams(DocBlock $doc, array $paramAnnotations): array
  60545. {
  60546. if (0 === \count($paramAnnotations)) {
  60547. return [];
  60548. }
  60549. $paramsStart = reset($paramAnnotations)->getStart();
  60550. $paramsEnd = end($paramAnnotations)->getEnd();
  60551. $otherAnnotations = [];
  60552. foreach ($doc->getAnnotations() as $annotation) {
  60553. if ($annotation->getStart() < $paramsStart || $annotation->getEnd() > $paramsEnd) {
  60554. continue;
  60555. }
  60556. if (self::PARAM_TAG !== $annotation->getTag()->getName()) {
  60557. $otherAnnotations[] = $annotation->getContent();
  60558. }
  60559. }
  60560. return $otherAnnotations;
  60561. }
  60562. private function findParamAnnotationByIdentifier(array $paramAnnotations, string $identifier): ?array
  60563. {
  60564. $blockLevel = 0;
  60565. $blockMatch = false;
  60566. $blockIndices = [];
  60567. $paramRegex = '/\*\h*@param\h*(?:|'.TypeExpression::REGEX_TYPES.'\h*)&?(?=\$\b)'.preg_quote($identifier).'\b/';
  60568. foreach ($paramAnnotations as $i => $param) {
  60569. $blockStart = Preg::match('/\s*{\s*/', $param->getContent());
  60570. $blockEndMatches = Preg::matchAll('/}[\*\s\n]*/', $param->getContent());
  60571. if (0 === $blockLevel && Preg::match($paramRegex, $param->getContent())) {
  60572. if ($blockStart) {
  60573. $blockMatch = true;
  60574. } else {
  60575. return [$i];
  60576. }
  60577. }
  60578. if ($blockStart) {
  60579. ++$blockLevel;
  60580. }
  60581. if (0 !== $blockEndMatches) {
  60582. $blockLevel -= $blockEndMatches;
  60583. }
  60584. if ($blockMatch) {
  60585. $blockIndices[] = $i;
  60586. if (0 === $blockLevel) {
  60587. return $blockIndices;
  60588. }
  60589. }
  60590. }
  60591. return null;
  60592. }
  60593. }
  60594. <?php
  60595. declare(strict_types=1);
  60596. namespace PhpCsFixer\Fixer\Phpdoc;
  60597. use PhpCsFixer\AbstractFixer;
  60598. use PhpCsFixer\DocBlock\DocBlock;
  60599. use PhpCsFixer\FixerDefinition\CodeSample;
  60600. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60601. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60602. use PhpCsFixer\Preg;
  60603. use PhpCsFixer\Tokenizer\Token;
  60604. use PhpCsFixer\Tokenizer\Tokens;
  60605. final class PhpdocAnnotationWithoutDotFixer extends AbstractFixer
  60606. {
  60607. private array $tags = ['throws', 'return', 'param', 'internal', 'deprecated', 'var', 'type'];
  60608. public function getDefinition(): FixerDefinitionInterface
  60609. {
  60610. return new FixerDefinition(
  60611. 'PHPDoc annotation descriptions should not be a sentence.',
  60612. [new CodeSample('<?php
  60613. /**
  60614. * @param string $bar Some string.
  60615. */
  60616. function foo ($bar) {}
  60617. ')]
  60618. );
  60619. }
  60620. public function getPriority(): int
  60621. {
  60622. return 17;
  60623. }
  60624. public function isCandidate(Tokens $tokens): bool
  60625. {
  60626. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  60627. }
  60628. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60629. {
  60630. foreach ($tokens as $index => $token) {
  60631. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  60632. continue;
  60633. }
  60634. $doc = new DocBlock($token->getContent());
  60635. $annotations = $doc->getAnnotations();
  60636. if (0 === \count($annotations)) {
  60637. continue;
  60638. }
  60639. foreach ($annotations as $annotation) {
  60640. if (
  60641. !$annotation->getTag()->valid() || !\in_array($annotation->getTag()->getName(), $this->tags, true)
  60642. ) {
  60643. continue;
  60644. }
  60645. $lineAfterAnnotation = $doc->getLine($annotation->getEnd() + 1);
  60646. if (null !== $lineAfterAnnotation) {
  60647. $lineAfterAnnotationTrimmed = ltrim($lineAfterAnnotation->getContent());
  60648. if ('' === $lineAfterAnnotationTrimmed || !str_starts_with($lineAfterAnnotationTrimmed, '*')) {
  60649. continue;
  60650. }
  60651. }
  60652. $content = $annotation->getContent();
  60653. if (
  60654. !Preg::match('/[.。]\h*$/u', $content)
  60655. || Preg::match('/[.。](?!\h*$)/u', $content, $matches)
  60656. ) {
  60657. continue;
  60658. }
  60659. $endLine = $doc->getLine($annotation->getEnd());
  60660. $endLine->setContent(Preg::replace('/(?<![.。])[.。]\h*(\H+)$/u', '\1', $endLine->getContent()));
  60661. $startLine = $doc->getLine($annotation->getStart());
  60662. $optionalTypeRegEx = $annotation->supportTypes()
  60663. ? \sprintf('(?:%s\s+(?:\$\w+\s+)?)?', preg_quote(implode('|', $annotation->getTypes()), '/'))
  60664. : '';
  60665. $content = Preg::replaceCallback(
  60666. '/^(\s*\*\s*@\w+\s+'.$optionalTypeRegEx.')(\p{Lu}?(?=\p{Ll}|\p{Zs}))(.*)$/',
  60667. static fn (array $matches): string => $matches[1].mb_strtolower($matches[2]).$matches[3],
  60668. $startLine->getContent(),
  60669. 1
  60670. );
  60671. $startLine->setContent($content);
  60672. }
  60673. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  60674. }
  60675. }
  60676. }
  60677. <?php
  60678. declare(strict_types=1);
  60679. namespace PhpCsFixer\Fixer\Phpdoc;
  60680. use PhpCsFixer\AbstractFixer;
  60681. use PhpCsFixer\DocBlock\DocBlock;
  60682. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60683. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60684. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  60685. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60686. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60687. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60688. use PhpCsFixer\FixerDefinition\CodeSample;
  60689. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60690. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60691. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  60692. use PhpCsFixer\Tokenizer\CT;
  60693. use PhpCsFixer\Tokenizer\FCT;
  60694. use PhpCsFixer\Tokenizer\Token;
  60695. use PhpCsFixer\Tokenizer\Tokens;
  60696. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  60697. /**
  60698. @phpstan-type
  60699. @phpstan-type
  60700. @implements
  60701. */
  60702. final class PhpdocLineSpanFixer extends AbstractFixer implements WhitespacesAwareFixerInterface, ConfigurableFixerInterface
  60703. {
  60704. /**
  60705. @use */
  60706. use ConfigurableFixerTrait;
  60707. private const PROPERTY_PART_KINDS = [
  60708. T_PUBLIC,
  60709. T_PROTECTED,
  60710. T_PRIVATE,
  60711. T_FINAL,
  60712. T_ABSTRACT,
  60713. T_COMMENT,
  60714. T_VAR,
  60715. T_STATIC,
  60716. T_STRING,
  60717. T_NS_SEPARATOR,
  60718. CT::T_ARRAY_TYPEHINT,
  60719. CT::T_NULLABLE_TYPE,
  60720. FCT::T_ATTRIBUTE,
  60721. FCT::T_READONLY,
  60722. FCT::T_PRIVATE_SET,
  60723. FCT::T_PROTECTED_SET,
  60724. FCT::T_PUBLIC_SET,
  60725. ];
  60726. public function getDefinition(): FixerDefinitionInterface
  60727. {
  60728. return new FixerDefinition(
  60729. 'Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only.',
  60730. [
  60731. new CodeSample("<?php\n\nclass Foo{\n /** @var bool */\n public \$var;\n}\n"),
  60732. new CodeSample(
  60733. "<?php\n\nclass Foo{\n /**\n * @var bool\n */\n public \$var;\n}\n",
  60734. ['property' => 'single']
  60735. ),
  60736. ]
  60737. );
  60738. }
  60739. public function getPriority(): int
  60740. {
  60741. return 7;
  60742. }
  60743. public function isCandidate(Tokens $tokens): bool
  60744. {
  60745. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  60746. }
  60747. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60748. {
  60749. return new FixerConfigurationResolver([
  60750. (new FixerOptionBuilder('const', 'Whether const blocks should be single or multi line.'))
  60751. ->setAllowedValues(['single', 'multi', null])
  60752. ->setDefault('multi')
  60753. ->getOption(),
  60754. (new FixerOptionBuilder('property', 'Whether property doc blocks should be single or multi line.'))
  60755. ->setAllowedValues(['single', 'multi', null])
  60756. ->setDefault('multi')
  60757. ->getOption(),
  60758. (new FixerOptionBuilder('method', 'Whether method doc blocks should be single or multi line.'))
  60759. ->setAllowedValues(['single', 'multi', null])
  60760. ->setDefault('multi')
  60761. ->getOption(),
  60762. ]);
  60763. }
  60764. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60765. {
  60766. $analyzer = new TokensAnalyzer($tokens);
  60767. foreach ($analyzer->getClassyElements() as $index => $element) {
  60768. if (!$this->hasDocBlock($tokens, $index)) {
  60769. continue;
  60770. }
  60771. $type = $element['type'];
  60772. if (!isset($this->configuration[$type])) {
  60773. continue;
  60774. }
  60775. $docIndex = $this->getDocBlockIndex($tokens, $index);
  60776. $doc = new DocBlock($tokens[$docIndex]->getContent());
  60777. if ('multi' === $this->configuration[$type]) {
  60778. $doc->makeMultiLine(WhitespacesAnalyzer::detectIndent($tokens, $docIndex), $this->whitespacesConfig->getLineEnding());
  60779. } elseif ('single' === $this->configuration[$type]) {
  60780. $doc->makeSingleLine();
  60781. }
  60782. $tokens->offsetSet($docIndex, new Token([T_DOC_COMMENT, $doc->getContent()]));
  60783. }
  60784. }
  60785. private function hasDocBlock(Tokens $tokens, int $index): bool
  60786. {
  60787. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  60788. return $tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT);
  60789. }
  60790. private function getDocBlockIndex(Tokens $tokens, int $index): int
  60791. {
  60792. do {
  60793. $index = $tokens->getPrevNonWhitespace($index);
  60794. if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  60795. $index = $tokens->getPrevTokenOfKind($index, [[T_ATTRIBUTE]]);
  60796. }
  60797. } while ($tokens[$index]->isGivenKind(self::PROPERTY_PART_KINDS));
  60798. return $index;
  60799. }
  60800. }
  60801. <?php
  60802. declare(strict_types=1);
  60803. namespace PhpCsFixer\Fixer\Phpdoc;
  60804. use PhpCsFixer\AbstractProxyFixer;
  60805. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  60806. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  60807. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60808. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60809. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60810. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60811. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60812. use PhpCsFixer\FixerDefinition\CodeSample;
  60813. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60814. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60815. use PhpCsFixer\Preg;
  60816. /**
  60817. @phpstan-type
  60818. @phpstan-type
  60819. @implements
  60820. */
  60821. final class PhpdocTagCasingFixer extends AbstractProxyFixer implements ConfigurableFixerInterface
  60822. {
  60823. /**
  60824. @use */
  60825. use ConfigurableFixerTrait;
  60826. public function getDefinition(): FixerDefinitionInterface
  60827. {
  60828. return new FixerDefinition(
  60829. 'Fixes casing of PHPDoc tags.',
  60830. [
  60831. new CodeSample("<?php\n/**\n * @inheritdoc\n */\n"),
  60832. new CodeSample("<?php\n/**\n * @inheritdoc\n * @Foo\n */\n", [
  60833. 'tags' => ['foo'],
  60834. ]),
  60835. ]
  60836. );
  60837. }
  60838. public function getPriority(): int
  60839. {
  60840. return parent::getPriority();
  60841. }
  60842. protected function configurePostNormalisation(): void
  60843. {
  60844. $replacements = [];
  60845. foreach ($this->configuration['tags'] as $tag) {
  60846. $replacements[$tag] = $tag;
  60847. }
  60848. $generalPhpdocTagRenameFixer = $this->proxyFixers['general_phpdoc_tag_rename'];
  60849. try {
  60850. $generalPhpdocTagRenameFixer->configure([
  60851. 'case_sensitive' => false,
  60852. 'fix_annotation' => true,
  60853. 'fix_inline' => true,
  60854. 'replacements' => $replacements,
  60855. ]);
  60856. } catch (InvalidConfigurationException $exception) {
  60857. throw new InvalidFixerConfigurationException(
  60858. $this->getName(),
  60859. Preg::replace('/^\[.+?\] /', '', $exception->getMessage()),
  60860. $exception
  60861. );
  60862. }
  60863. }
  60864. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60865. {
  60866. return new FixerConfigurationResolver([
  60867. (new FixerOptionBuilder('tags', 'List of tags to fix with their expected casing.'))
  60868. ->setAllowedTypes(['string[]'])
  60869. ->setDefault(['inheritDoc'])
  60870. ->getOption(),
  60871. ]);
  60872. }
  60873. protected function createProxyFixers(): array
  60874. {
  60875. return [new GeneralPhpdocTagRenameFixer()];
  60876. }
  60877. }
  60878. <?php
  60879. declare(strict_types=1);
  60880. namespace PhpCsFixer\Fixer\Phpdoc;
  60881. use PhpCsFixer\AbstractFixer;
  60882. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  60883. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  60884. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  60885. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  60886. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  60887. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  60888. use PhpCsFixer\FixerDefinition\CodeSample;
  60889. use PhpCsFixer\FixerDefinition\FixerDefinition;
  60890. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  60891. use PhpCsFixer\Preg;
  60892. use PhpCsFixer\Tokenizer\Token;
  60893. use PhpCsFixer\Tokenizer\Tokens;
  60894. /**
  60895. @phpstan-type
  60896. @phpstan-type
  60897. @implements
  60898. */
  60899. final class AlignMultilineCommentFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  60900. {
  60901. /**
  60902. @use */
  60903. use ConfigurableFixerTrait;
  60904. private ?array $tokenKinds = null;
  60905. public function getDefinition(): FixerDefinitionInterface
  60906. {
  60907. return new FixerDefinition(
  60908. 'Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.',
  60909. [
  60910. new CodeSample(
  60911. '<?php
  60912. /**
  60913. * This is a DOC Comment
  60914. with a line not prefixed with asterisk
  60915. */
  60916. '
  60917. ),
  60918. new CodeSample(
  60919. '<?php
  60920. /*
  60921. * This is a doc-like multiline comment
  60922. */
  60923. ',
  60924. ['comment_type' => 'phpdocs_like']
  60925. ),
  60926. new CodeSample(
  60927. '<?php
  60928. /*
  60929. * This is a doc-like multiline comment
  60930. with a line not prefixed with asterisk
  60931. */
  60932. ',
  60933. ['comment_type' => 'all_multiline']
  60934. ),
  60935. ]
  60936. );
  60937. }
  60938. public function getPriority(): int
  60939. {
  60940. return 27;
  60941. }
  60942. public function isCandidate(Tokens $tokens): bool
  60943. {
  60944. return $tokens->isAnyTokenKindsFound($this->tokenKinds);
  60945. }
  60946. protected function configurePostNormalisation(): void
  60947. {
  60948. $this->tokenKinds = [T_DOC_COMMENT];
  60949. if ('phpdocs_only' !== $this->configuration['comment_type']) {
  60950. $this->tokenKinds[] = T_COMMENT;
  60951. }
  60952. }
  60953. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  60954. {
  60955. $lineEnding = $this->whitespacesConfig->getLineEnding();
  60956. foreach ($tokens as $index => $token) {
  60957. if (!$token->isGivenKind($this->tokenKinds)) {
  60958. continue;
  60959. }
  60960. $whitespace = '';
  60961. $previousIndex = $index - 1;
  60962. if ($tokens[$previousIndex]->isWhitespace()) {
  60963. $whitespace = $tokens[$previousIndex]->getContent();
  60964. --$previousIndex;
  60965. }
  60966. if ($tokens[$previousIndex]->isGivenKind(T_OPEN_TAG)) {
  60967. $whitespace = Preg::replace('/\S/', '', $tokens[$previousIndex]->getContent()).$whitespace;
  60968. }
  60969. if (!Preg::match('/\R(\h*)$/', $whitespace, $matches)) {
  60970. continue;
  60971. }
  60972. if ($token->isGivenKind(T_COMMENT) && 'all_multiline' !== $this->configuration['comment_type'] && Preg::match('/\R(?:\R|\s*[^\s\*])/', $token->getContent())) {
  60973. continue;
  60974. }
  60975. $indentation = $matches[1];
  60976. $lines = Preg::split('/\R/u', $token->getContent());
  60977. foreach ($lines as $lineNumber => $line) {
  60978. if (0 === $lineNumber) {
  60979. continue;
  60980. }
  60981. $line = ltrim($line);
  60982. if ($token->isGivenKind(T_COMMENT) && (!isset($line[0]) || '*' !== $line[0])) {
  60983. continue;
  60984. }
  60985. if (!isset($line[0])) {
  60986. $line = '*';
  60987. } elseif ('*' !== $line[0]) {
  60988. $line = '* '.$line;
  60989. }
  60990. $lines[$lineNumber] = $indentation.' '.$line;
  60991. }
  60992. $tokens[$index] = new Token([$token->getId(), implode($lineEnding, $lines)]);
  60993. }
  60994. }
  60995. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  60996. {
  60997. return new FixerConfigurationResolver([
  60998. (new FixerOptionBuilder('comment_type', 'Whether to fix PHPDoc comments only (`phpdocs_only`), any multi-line comment whose lines all start with an asterisk (`phpdocs_like`) or any multi-line comment (`all_multiline`).'))
  60999. ->setAllowedValues(['phpdocs_only', 'phpdocs_like', 'all_multiline'])
  61000. ->setDefault('phpdocs_only')
  61001. ->getOption(),
  61002. ]);
  61003. }
  61004. }
  61005. <?php
  61006. declare(strict_types=1);
  61007. namespace PhpCsFixer\Fixer\Phpdoc;
  61008. use PhpCsFixer\AbstractProxyFixer;
  61009. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  61010. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  61011. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  61012. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  61013. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  61014. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  61015. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  61016. use PhpCsFixer\FixerDefinition\CodeSample;
  61017. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61018. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61019. use PhpCsFixer\Preg;
  61020. /**
  61021. @phpstan-type
  61022. @phpstan-type
  61023. @implements
  61024. */
  61025. final class PhpdocNoAliasTagFixer extends AbstractProxyFixer implements ConfigurableFixerInterface
  61026. {
  61027. /**
  61028. @use */
  61029. use ConfigurableFixerTrait;
  61030. public function getDefinition(): FixerDefinitionInterface
  61031. {
  61032. return new FixerDefinition(
  61033. 'No alias PHPDoc tags should be used.',
  61034. [
  61035. new CodeSample(
  61036. '<?php
  61037. /**
  61038. * @property string $foo
  61039. * @property-read string $bar
  61040. *
  61041. * @link baz
  61042. */
  61043. final class Example
  61044. {
  61045. }
  61046. '
  61047. ),
  61048. new CodeSample(
  61049. '<?php
  61050. /**
  61051. * @property string $foo
  61052. * @property-read string $bar
  61053. *
  61054. * @link baz
  61055. */
  61056. final class Example
  61057. {
  61058. }
  61059. ',
  61060. ['replacements' => ['link' => 'website']]
  61061. ),
  61062. ]
  61063. );
  61064. }
  61065. public function getPriority(): int
  61066. {
  61067. return parent::getPriority();
  61068. }
  61069. protected function configurePostNormalisation(): void
  61070. {
  61071. $generalPhpdocTagRenameFixer = $this->proxyFixers['general_phpdoc_tag_rename'];
  61072. try {
  61073. $generalPhpdocTagRenameFixer->configure([
  61074. 'fix_annotation' => true,
  61075. 'fix_inline' => false,
  61076. 'replacements' => $this->configuration['replacements'],
  61077. 'case_sensitive' => true,
  61078. ]);
  61079. } catch (InvalidConfigurationException $exception) {
  61080. throw new InvalidFixerConfigurationException(
  61081. $this->getName(),
  61082. Preg::replace('/^\[.+?\] /', '', $exception->getMessage()),
  61083. $exception
  61084. );
  61085. }
  61086. }
  61087. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  61088. {
  61089. return new FixerConfigurationResolver([
  61090. (new FixerOptionBuilder('replacements', 'Mapping between replaced annotations with new ones.'))
  61091. ->setAllowedTypes(['array<string, string>'])
  61092. ->setDefault([
  61093. 'property-read' => 'property',
  61094. 'property-write' => 'property',
  61095. 'type' => 'var',
  61096. 'link' => 'see',
  61097. ])
  61098. ->getOption(),
  61099. ]);
  61100. }
  61101. protected function createProxyFixers(): array
  61102. {
  61103. return [new GeneralPhpdocTagRenameFixer()];
  61104. }
  61105. }
  61106. <?php
  61107. declare(strict_types=1);
  61108. namespace PhpCsFixer\Fixer\Phpdoc;
  61109. use PhpCsFixer\AbstractFixer;
  61110. use PhpCsFixer\DocBlock\Annotation;
  61111. use PhpCsFixer\DocBlock\DocBlock;
  61112. use PhpCsFixer\DocBlock\TypeExpression;
  61113. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  61114. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  61115. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  61116. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  61117. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  61118. use PhpCsFixer\FixerDefinition\CodeSample;
  61119. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61120. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61121. use PhpCsFixer\Preg;
  61122. use PhpCsFixer\Tokenizer\Token;
  61123. use PhpCsFixer\Tokenizer\Tokens;
  61124. /**
  61125. @phpstan-type
  61126. @phpstan-type
  61127. @implements
  61128. */
  61129. final class PhpdocTypesOrderFixer extends AbstractFixer implements ConfigurableFixerInterface
  61130. {
  61131. /**
  61132. @use */
  61133. use ConfigurableFixerTrait;
  61134. public function getDefinition(): FixerDefinitionInterface
  61135. {
  61136. return new FixerDefinition(
  61137. 'Sorts PHPDoc types.',
  61138. [
  61139. new CodeSample(
  61140. '<?php
  61141. /**
  61142. * @param string|null $bar
  61143. */
  61144. '
  61145. ),
  61146. new CodeSample(
  61147. '<?php
  61148. /**
  61149. * @param null|string $bar
  61150. */
  61151. ',
  61152. ['null_adjustment' => 'always_last']
  61153. ),
  61154. new CodeSample(
  61155. '<?php
  61156. /**
  61157. * @param null|string|int|\Foo $bar
  61158. */
  61159. ',
  61160. ['sort_algorithm' => 'alpha']
  61161. ),
  61162. new CodeSample(
  61163. '<?php
  61164. /**
  61165. * @param null|string|int|\Foo $bar
  61166. */
  61167. ',
  61168. [
  61169. 'sort_algorithm' => 'alpha',
  61170. 'null_adjustment' => 'always_last',
  61171. ]
  61172. ),
  61173. new CodeSample(
  61174. '<?php
  61175. /**
  61176. * @param null|string|int|\Foo $bar
  61177. */
  61178. ',
  61179. [
  61180. 'sort_algorithm' => 'alpha',
  61181. 'null_adjustment' => 'none',
  61182. ]
  61183. ),
  61184. new CodeSample(
  61185. '<?php
  61186. /**
  61187. * @param Aaa|AA $bar
  61188. */
  61189. ',
  61190. ['case_sensitive' => true]
  61191. ),
  61192. ]
  61193. );
  61194. }
  61195. public function getPriority(): int
  61196. {
  61197. return 0;
  61198. }
  61199. public function isCandidate(Tokens $tokens): bool
  61200. {
  61201. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61202. }
  61203. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  61204. {
  61205. return new FixerConfigurationResolver([
  61206. (new FixerOptionBuilder('sort_algorithm', 'The sorting algorithm to apply.'))
  61207. ->setAllowedValues(['alpha', 'none'])
  61208. ->setDefault('alpha')
  61209. ->getOption(),
  61210. (new FixerOptionBuilder('null_adjustment', 'Forces the position of `null` (overrides `sort_algorithm`).'))
  61211. ->setAllowedValues(['always_first', 'always_last', 'none'])
  61212. ->setDefault('always_first')
  61213. ->getOption(),
  61214. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  61215. ->setAllowedTypes(['bool'])
  61216. ->setDefault(false)
  61217. ->getOption(),
  61218. ]);
  61219. }
  61220. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61221. {
  61222. foreach ($tokens as $index => $token) {
  61223. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61224. continue;
  61225. }
  61226. $doc = new DocBlock($token->getContent());
  61227. $annotations = $doc->getAnnotationsOfType(Annotation::getTagsWithTypes());
  61228. if (0 === \count($annotations)) {
  61229. continue;
  61230. }
  61231. foreach ($annotations as $annotation) {
  61232. if (null !== $annotation->getTypeExpression()) {
  61233. $annotation->setTypes(
  61234. $this->sortTypes(
  61235. $annotation->getTypeExpression()
  61236. )
  61237. );
  61238. }
  61239. $line = $doc->getLine($annotation->getStart());
  61240. $line->setContent(Preg::replaceCallback('/\*\h*@method\h+'.TypeExpression::REGEX_TYPES.'\h+\K(?&callable)/', function (array $matches) {
  61241. $typeExpression = new TypeExpression($matches[0], null, []);
  61242. return implode('|', $this->sortTypes($typeExpression));
  61243. }, $line->getContent()));
  61244. }
  61245. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  61246. }
  61247. }
  61248. private function sortTypes(TypeExpression $typeExpression): array
  61249. {
  61250. $normalizeType = static fn (string $type): string => Preg::replace('/^\(*\??\\\?/', '', $type);
  61251. $sortedTypeExpression = $typeExpression->sortTypes(
  61252. function (TypeExpression $a, TypeExpression $b) use ($normalizeType): int {
  61253. $a = $normalizeType($a->toString());
  61254. $b = $normalizeType($b->toString());
  61255. $lowerCaseA = strtolower($a);
  61256. $lowerCaseB = strtolower($b);
  61257. if ('none' !== $this->configuration['null_adjustment']) {
  61258. if ('null' === $lowerCaseA && 'null' !== $lowerCaseB) {
  61259. return 'always_last' === $this->configuration['null_adjustment'] ? 1 : -1;
  61260. }
  61261. if ('null' !== $lowerCaseA && 'null' === $lowerCaseB) {
  61262. return 'always_last' === $this->configuration['null_adjustment'] ? -1 : 1;
  61263. }
  61264. }
  61265. if ('alpha' === $this->configuration['sort_algorithm']) {
  61266. return true === $this->configuration['case_sensitive'] ? $a <=> $b : strcasecmp($a, $b);
  61267. }
  61268. return 0;
  61269. }
  61270. );
  61271. return $sortedTypeExpression->getTypes();
  61272. }
  61273. }
  61274. <?php
  61275. declare(strict_types=1);
  61276. namespace PhpCsFixer\Fixer\Phpdoc;
  61277. use PhpCsFixer\AbstractFixer;
  61278. use PhpCsFixer\FixerDefinition\CodeSample;
  61279. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61280. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61281. use PhpCsFixer\Preg;
  61282. use PhpCsFixer\Tokenizer\Token;
  61283. use PhpCsFixer\Tokenizer\Tokens;
  61284. final class PhpdocTrimFixer extends AbstractFixer
  61285. {
  61286. public function getDefinition(): FixerDefinitionInterface
  61287. {
  61288. return new FixerDefinition(
  61289. 'PHPDoc should start and end with content, excluding the very first and last line of the docblocks.',
  61290. [new CodeSample('<?php
  61291. /**
  61292. *
  61293. * Foo must be final class.
  61294. *
  61295. *
  61296. */
  61297. final class Foo {}
  61298. ')]
  61299. );
  61300. }
  61301. public function getPriority(): int
  61302. {
  61303. return -5;
  61304. }
  61305. public function isCandidate(Tokens $tokens): bool
  61306. {
  61307. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61308. }
  61309. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61310. {
  61311. foreach ($tokens as $index => $token) {
  61312. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61313. continue;
  61314. }
  61315. $content = $token->getContent();
  61316. $content = $this->fixStart($content);
  61317. $content = $this->fixEnd($content);
  61318. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  61319. }
  61320. }
  61321. private function fixStart(string $content): string
  61322. {
  61323. return Preg::replace(
  61324. '~
  61325. (^/\*\*) # DocComment begin
  61326. (?:
  61327. \R\h*(?:\*\h*)? # lines without useful content
  61328. (?!\R\h*\*/) # not followed by a DocComment end
  61329. )+
  61330. (\R\h*(?:\*\h*)?\S) # first line with useful content
  61331. ~x',
  61332. '$1$2',
  61333. $content
  61334. );
  61335. }
  61336. private function fixEnd(string $content): string
  61337. {
  61338. return Preg::replace(
  61339. '~
  61340. (\R\h*(?:\*\h*)?\S.*?) # last line with useful content
  61341. (?:
  61342. (?<!/\*\*) # not preceded by a DocComment start
  61343. \R\h*(?:\*\h*)? # lines without useful content
  61344. )+
  61345. (\R\h*\*/$) # DocComment end
  61346. ~xu',
  61347. '$1$2',
  61348. $content
  61349. );
  61350. }
  61351. }
  61352. <?php
  61353. declare(strict_types=1);
  61354. namespace PhpCsFixer\Fixer\Phpdoc;
  61355. use PhpCsFixer\AbstractFixer;
  61356. use PhpCsFixer\FixerDefinition\CodeSample;
  61357. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61358. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61359. use PhpCsFixer\Preg;
  61360. use PhpCsFixer\Tokenizer\Token;
  61361. use PhpCsFixer\Tokenizer\Tokens;
  61362. final class PhpdocVarAnnotationCorrectOrderFixer extends AbstractFixer
  61363. {
  61364. public function getDefinition(): FixerDefinitionInterface
  61365. {
  61366. return new FixerDefinition(
  61367. '`@var` and `@type` annotations must have type and name in the correct order.',
  61368. [new CodeSample('<?php
  61369. /** @var $foo int */
  61370. $foo = 2 + 2;
  61371. ')]
  61372. );
  61373. }
  61374. public function getPriority(): int
  61375. {
  61376. return 0;
  61377. }
  61378. public function isCandidate(Tokens $tokens): bool
  61379. {
  61380. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61381. }
  61382. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61383. {
  61384. foreach ($tokens as $index => $token) {
  61385. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61386. continue;
  61387. }
  61388. if (!str_contains(strtolower($token->getContent()), strtolower('@var')) && !str_contains(strtolower($token->getContent()), strtolower('@type'))) {
  61389. continue;
  61390. }
  61391. $newContent = Preg::replace(
  61392. '/(@(?:type|var)\s*)(\$\S+)(\h+)([^\$](?:[^<\s]|<[^>]*>)*)(\s|\*)/i',
  61393. '$1$4$3$2$5',
  61394. $token->getContent()
  61395. );
  61396. if ($newContent === $token->getContent()) {
  61397. continue;
  61398. }
  61399. $tokens[$index] = new Token([$token->getId(), $newContent]);
  61400. }
  61401. }
  61402. }
  61403. <?php
  61404. declare(strict_types=1);
  61405. namespace PhpCsFixer\Fixer\Phpdoc;
  61406. use PhpCsFixer\AbstractFixer;
  61407. use PhpCsFixer\FixerDefinition\CodeSample;
  61408. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61409. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61410. use PhpCsFixer\Preg;
  61411. use PhpCsFixer\Tokenizer\Token;
  61412. use PhpCsFixer\Tokenizer\Tokens;
  61413. final class PhpdocSingleLineVarSpacingFixer extends AbstractFixer
  61414. {
  61415. public function getDefinition(): FixerDefinitionInterface
  61416. {
  61417. return new FixerDefinition(
  61418. 'Single line `@var` PHPDoc should have proper spacing.',
  61419. [new CodeSample("<?php /**@var MyClass \$a */\n\$a = test();\n")]
  61420. );
  61421. }
  61422. public function getPriority(): int
  61423. {
  61424. return -10;
  61425. }
  61426. public function isCandidate(Tokens $tokens): bool
  61427. {
  61428. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  61429. }
  61430. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61431. {
  61432. foreach ($tokens as $index => $token) {
  61433. if (!$token->isComment()) {
  61434. continue;
  61435. }
  61436. $content = $token->getContent();
  61437. $fixedContent = $this->fixTokenContent($content);
  61438. if ($content !== $fixedContent) {
  61439. $tokens[$index] = new Token([T_DOC_COMMENT, $fixedContent]);
  61440. }
  61441. }
  61442. }
  61443. private function fixTokenContent(string $content): string
  61444. {
  61445. return Preg::replaceCallback(
  61446. '#^/\*\*\h*@var\h+(\S+)\h*(\$\S+)?\h*([^\n]*)\*/$#',
  61447. static function (array $matches) {
  61448. $content = '/** @var';
  61449. for ($i = 1, $m = \count($matches); $i < $m; ++$i) {
  61450. if ('' !== $matches[$i]) {
  61451. $content .= ' '.$matches[$i];
  61452. }
  61453. }
  61454. return rtrim($content).' */';
  61455. },
  61456. $content
  61457. );
  61458. }
  61459. }
  61460. <?php
  61461. declare(strict_types=1);
  61462. namespace PhpCsFixer\Fixer\Phpdoc;
  61463. use PhpCsFixer\AbstractFixer;
  61464. use PhpCsFixer\FixerDefinition\CodeSample;
  61465. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61466. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61467. use PhpCsFixer\Tokenizer\Token;
  61468. use PhpCsFixer\Tokenizer\Tokens;
  61469. final class NoBlankLinesAfterPhpdocFixer extends AbstractFixer
  61470. {
  61471. public function isCandidate(Tokens $tokens): bool
  61472. {
  61473. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61474. }
  61475. public function getDefinition(): FixerDefinitionInterface
  61476. {
  61477. return new FixerDefinition(
  61478. 'There should not be blank lines between docblock and the documented element.',
  61479. [
  61480. new CodeSample(
  61481. '<?php
  61482. /**
  61483. * This is the bar class.
  61484. */
  61485. class Bar {}
  61486. '
  61487. ),
  61488. ]
  61489. );
  61490. }
  61491. public function getPriority(): int
  61492. {
  61493. return -20;
  61494. }
  61495. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61496. {
  61497. static $forbiddenSuccessors = [
  61498. T_BREAK,
  61499. T_COMMENT,
  61500. T_CONTINUE,
  61501. T_DECLARE,
  61502. T_DOC_COMMENT,
  61503. T_GOTO,
  61504. T_INCLUDE,
  61505. T_INCLUDE_ONCE,
  61506. T_NAMESPACE,
  61507. T_REQUIRE,
  61508. T_REQUIRE_ONCE,
  61509. T_RETURN,
  61510. T_THROW,
  61511. T_USE,
  61512. T_WHITESPACE,
  61513. ];
  61514. foreach ($tokens as $index => $token) {
  61515. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61516. continue;
  61517. }
  61518. $next = $tokens->getNextNonWhitespace($index);
  61519. if ($index + 2 === $next && false === $tokens[$next]->isGivenKind($forbiddenSuccessors)) {
  61520. $this->fixWhitespace($tokens, $index + 1);
  61521. }
  61522. }
  61523. }
  61524. private function fixWhitespace(Tokens $tokens, int $index): void
  61525. {
  61526. $content = $tokens[$index]->getContent();
  61527. if (substr_count($content, "\n") > 1) {
  61528. $tokens[$index] = new Token([T_WHITESPACE, substr($content, strrpos($content, "\n"))]);
  61529. }
  61530. }
  61531. }
  61532. <?php
  61533. declare(strict_types=1);
  61534. namespace PhpCsFixer\Fixer\Phpdoc;
  61535. use PhpCsFixer\AbstractPhpdocTypesFixer;
  61536. use PhpCsFixer\DocBlock\TypeExpression;
  61537. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  61538. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  61539. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  61540. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  61541. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  61542. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  61543. use PhpCsFixer\FixerDefinition\CodeSample;
  61544. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61545. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61546. /**
  61547. @phpstan-type
  61548. @phpstan-type
  61549. @implements
  61550. */
  61551. final class PhpdocTypesFixer extends AbstractPhpdocTypesFixer implements ConfigurableFixerInterface
  61552. {
  61553. /**
  61554. @use */
  61555. use ConfigurableFixerTrait;
  61556. private const POSSIBLE_TYPES = [
  61557. 'alias' => [
  61558. 'boolean',
  61559. 'double',
  61560. 'integer',
  61561. ],
  61562. 'meta' => [
  61563. '$this',
  61564. 'false',
  61565. 'mixed',
  61566. 'parent',
  61567. 'resource',
  61568. 'scalar',
  61569. 'self',
  61570. 'static',
  61571. 'true',
  61572. 'void',
  61573. ],
  61574. 'simple' => [
  61575. 'array',
  61576. 'bool',
  61577. 'callable',
  61578. 'float',
  61579. 'int',
  61580. 'iterable',
  61581. 'null',
  61582. 'object',
  61583. 'string',
  61584. ],
  61585. ];
  61586. private array $typesSetToFix;
  61587. public function getDefinition(): FixerDefinitionInterface
  61588. {
  61589. return new FixerDefinition(
  61590. 'The correct case must be used for standard PHP types in PHPDoc.',
  61591. [
  61592. new CodeSample(
  61593. '<?php
  61594. /**
  61595. * @param STRING|String[] $bar
  61596. *
  61597. * @return inT[]
  61598. */
  61599. '
  61600. ),
  61601. new CodeSample(
  61602. '<?php
  61603. /**
  61604. * @param BOOL $foo
  61605. *
  61606. * @return MIXED
  61607. */
  61608. ',
  61609. ['groups' => ['simple', 'alias']]
  61610. ),
  61611. ]
  61612. );
  61613. }
  61614. public function getPriority(): int
  61615. {
  61616. return 16;
  61617. }
  61618. protected function configurePostNormalisation(): void
  61619. {
  61620. $typesToFix = array_merge(...array_map(static fn (string $group): array => self::POSSIBLE_TYPES[$group], $this->configuration['groups']));
  61621. $this->typesSetToFix = array_combine($typesToFix, array_fill(0, \count($typesToFix), true));
  61622. }
  61623. protected function normalize(string $type): string
  61624. {
  61625. $typeExpression = new TypeExpression($type, null, []);
  61626. $newTypeExpression = $typeExpression->mapTypes(function (TypeExpression $type) {
  61627. if ($type->isUnionType()) {
  61628. return $type;
  61629. }
  61630. $value = $type->toString();
  61631. $valueLower = strtolower($value);
  61632. if (isset($this->typesSetToFix[$valueLower])) {
  61633. return new TypeExpression($valueLower, null, []);
  61634. }
  61635. return $type;
  61636. });
  61637. return $newTypeExpression->toString();
  61638. }
  61639. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  61640. {
  61641. $possibleGroups = array_keys(self::POSSIBLE_TYPES);
  61642. return new FixerConfigurationResolver([
  61643. (new FixerOptionBuilder('groups', 'Type groups to fix.'))
  61644. ->setAllowedTypes(['string[]'])
  61645. ->setAllowedValues([new AllowedValueSubset($possibleGroups)])
  61646. ->setDefault($possibleGroups)
  61647. ->getOption(),
  61648. ]);
  61649. }
  61650. }
  61651. <?php
  61652. declare(strict_types=1);
  61653. namespace PhpCsFixer\Fixer\Phpdoc;
  61654. use PhpCsFixer\AbstractFixer;
  61655. use PhpCsFixer\DocBlock\Annotation;
  61656. use PhpCsFixer\DocBlock\DocBlock;
  61657. use PhpCsFixer\FixerDefinition\CodeSample;
  61658. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61659. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61660. use PhpCsFixer\Tokenizer\Token;
  61661. use PhpCsFixer\Tokenizer\Tokens;
  61662. final class PhpdocNoEmptyReturnFixer extends AbstractFixer
  61663. {
  61664. public function isCandidate(Tokens $tokens): bool
  61665. {
  61666. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61667. }
  61668. public function getDefinition(): FixerDefinitionInterface
  61669. {
  61670. return new FixerDefinition(
  61671. '`@return void` and `@return null` annotations must be removed from PHPDoc.',
  61672. [
  61673. new CodeSample(
  61674. '<?php
  61675. /**
  61676. * @return null
  61677. */
  61678. function foo() {}
  61679. '
  61680. ),
  61681. new CodeSample(
  61682. '<?php
  61683. /**
  61684. * @return void
  61685. */
  61686. function foo() {}
  61687. '
  61688. ),
  61689. ]
  61690. );
  61691. }
  61692. public function getPriority(): int
  61693. {
  61694. return 4;
  61695. }
  61696. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61697. {
  61698. foreach ($tokens as $index => $token) {
  61699. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61700. continue;
  61701. }
  61702. $doc = new DocBlock($token->getContent());
  61703. $annotations = $doc->getAnnotationsOfType('return');
  61704. if (0 === \count($annotations)) {
  61705. continue;
  61706. }
  61707. foreach ($annotations as $annotation) {
  61708. $this->fixAnnotation($annotation);
  61709. }
  61710. $newContent = $doc->getContent();
  61711. if ($newContent === $token->getContent()) {
  61712. continue;
  61713. }
  61714. if ('' === $newContent) {
  61715. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  61716. continue;
  61717. }
  61718. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  61719. }
  61720. }
  61721. private function fixAnnotation(Annotation $annotation): void
  61722. {
  61723. $types = $annotation->getNormalizedTypes();
  61724. if (1 === \count($types) && ('null' === $types[0] || 'void' === $types[0])) {
  61725. $annotation->remove();
  61726. }
  61727. }
  61728. }
  61729. <?php
  61730. declare(strict_types=1);
  61731. namespace PhpCsFixer\Fixer\Phpdoc;
  61732. use PhpCsFixer\AbstractFixer;
  61733. use PhpCsFixer\DocBlock\Annotation;
  61734. use PhpCsFixer\DocBlock\DocBlock;
  61735. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  61736. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  61737. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  61738. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  61739. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  61740. use PhpCsFixer\FixerDefinition\CodeSample;
  61741. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61742. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61743. use PhpCsFixer\Preg;
  61744. use PhpCsFixer\Tokenizer\Token;
  61745. use PhpCsFixer\Tokenizer\Tokens;
  61746. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  61747. /**
  61748. @phpstan-type
  61749. @phpstan-type
  61750. @implements
  61751. */
  61752. final class PhpdocSeparationFixer extends AbstractFixer implements ConfigurableFixerInterface
  61753. {
  61754. /**
  61755. @use */
  61756. use ConfigurableFixerTrait;
  61757. public const OPTION_GROUPS_DEFAULT = [
  61758. ['author', 'copyright', 'license'],
  61759. ['category', 'package', 'subpackage'],
  61760. ['property', 'property-read', 'property-write'],
  61761. ['deprecated', 'link', 'see', 'since'],
  61762. ];
  61763. private array $groups;
  61764. public function getDefinition(): FixerDefinitionInterface
  61765. {
  61766. $code = <<<'EOF'
  61767. <?php
  61768. /**
  61769. * Hello there!
  61770. *
  61771. * @author John Doe
  61772. * @custom Test!
  61773. *
  61774. * @throws Exception|RuntimeException foo
  61775. * @param string $foo
  61776. *
  61777. * @param bool $bar Bar
  61778. * @return int Return the number of changes.
  61779. */
  61780. EOF;
  61781. return new FixerDefinition(
  61782. 'Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other. Annotations of a different type are separated by a single blank line.',
  61783. [
  61784. new CodeSample($code),
  61785. new CodeSample($code, ['groups' => [
  61786. ['deprecated', 'link', 'see', 'since'],
  61787. ['author', 'copyright', 'license'],
  61788. ['category', 'package', 'subpackage'],
  61789. ['property', 'property-read', 'property-write'],
  61790. ['param', 'return'],
  61791. ]]),
  61792. new CodeSample($code, ['groups' => [
  61793. ['author', 'throws', 'custom'],
  61794. ['return', 'param'],
  61795. ]]),
  61796. new CodeSample(
  61797. <<<'EOF'
  61798. <?php
  61799. /**
  61800. * @ORM\Id
  61801. *
  61802. * @ORM\GeneratedValue
  61803. * @Assert\NotNull
  61804. *
  61805. * @Assert\Type("string")
  61806. */
  61807. EOF,
  61808. ['groups' => [['ORM\*'], ['Assert\*']]],
  61809. ),
  61810. new CodeSample($code, ['skip_unlisted_annotations' => true]),
  61811. ],
  61812. );
  61813. }
  61814. public function getPriority(): int
  61815. {
  61816. return -3;
  61817. }
  61818. public function isCandidate(Tokens $tokens): bool
  61819. {
  61820. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61821. }
  61822. protected function configurePostNormalisation(): void
  61823. {
  61824. $this->groups = $this->configuration['groups'];
  61825. }
  61826. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  61827. {
  61828. foreach ($tokens as $index => $token) {
  61829. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  61830. continue;
  61831. }
  61832. $doc = new DocBlock($token->getContent());
  61833. $this->fixDescription($doc);
  61834. $this->fixAnnotations($doc);
  61835. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  61836. }
  61837. }
  61838. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  61839. {
  61840. $allowTagToBelongToOnlyOneGroup = static function (array $groups): bool {
  61841. $tags = [];
  61842. foreach ($groups as $groupIndex => $group) {
  61843. foreach ($group as $member) {
  61844. if (isset($tags[$member])) {
  61845. if ($groupIndex === $tags[$member]) {
  61846. throw new InvalidOptionsException(
  61847. 'The option "groups" value is invalid. '
  61848. .'The "'.$member.'" tag is specified more than once.'
  61849. );
  61850. }
  61851. throw new InvalidOptionsException(
  61852. 'The option "groups" value is invalid. '
  61853. .'The "'.$member.'" tag belongs to more than one group.'
  61854. );
  61855. }
  61856. $tags[$member] = $groupIndex;
  61857. }
  61858. }
  61859. return true;
  61860. };
  61861. return new FixerConfigurationResolver([
  61862. (new FixerOptionBuilder('groups', 'Sets of annotation types to be grouped together. Use `*` to match any tag character.'))
  61863. ->setAllowedTypes(['string[][]'])
  61864. ->setDefault(self::OPTION_GROUPS_DEFAULT)
  61865. ->setAllowedValues([$allowTagToBelongToOnlyOneGroup])
  61866. ->getOption(),
  61867. (new FixerOptionBuilder('skip_unlisted_annotations', 'Whether to skip annotations that are not listed in any group.'))
  61868. ->setAllowedTypes(['bool'])
  61869. ->setDefault(false)
  61870. ->getOption(),
  61871. ]);
  61872. }
  61873. private function fixDescription(DocBlock $doc): void
  61874. {
  61875. foreach ($doc->getLines() as $index => $line) {
  61876. if ($line->containsATag()) {
  61877. break;
  61878. }
  61879. if ($line->containsUsefulContent()) {
  61880. $next = $doc->getLine($index + 1);
  61881. if (null !== $next && $next->containsATag()) {
  61882. $line->addBlank();
  61883. break;
  61884. }
  61885. }
  61886. }
  61887. }
  61888. private function fixAnnotations(DocBlock $doc): void
  61889. {
  61890. foreach ($doc->getAnnotations() as $index => $annotation) {
  61891. $next = $doc->getAnnotation($index + 1);
  61892. if (null === $next) {
  61893. break;
  61894. }
  61895. $shouldBeTogether = $this->shouldBeTogether($annotation, $next, $this->groups);
  61896. if (true === $shouldBeTogether) {
  61897. $this->ensureAreTogether($doc, $annotation, $next);
  61898. } elseif (false === $shouldBeTogether || false === $this->configuration['skip_unlisted_annotations']) {
  61899. $this->ensureAreSeparate($doc, $annotation, $next);
  61900. }
  61901. }
  61902. }
  61903. private function ensureAreTogether(DocBlock $doc, Annotation $first, Annotation $second): void
  61904. {
  61905. $pos = $first->getEnd();
  61906. $final = $second->getStart();
  61907. for (++$pos; $pos < $final; ++$pos) {
  61908. $doc->getLine($pos)->remove();
  61909. }
  61910. }
  61911. private function ensureAreSeparate(DocBlock $doc, Annotation $first, Annotation $second): void
  61912. {
  61913. $pos = $first->getEnd();
  61914. $final = $second->getStart() - 1;
  61915. if ($pos === $final) {
  61916. $doc->getLine($pos)->addBlank();
  61917. return;
  61918. }
  61919. for (++$pos; $pos < $final; ++$pos) {
  61920. $doc->getLine($pos)->remove();
  61921. }
  61922. }
  61923. private function shouldBeTogether(Annotation $first, Annotation $second, array $groups): ?bool
  61924. {
  61925. $firstName = $this->tagName($first);
  61926. $secondName = $this->tagName($second);
  61927. if (null === $firstName || null === $secondName) {
  61928. return null;
  61929. }
  61930. if ($firstName === $secondName) {
  61931. return true;
  61932. }
  61933. foreach ($groups as $group) {
  61934. $firstTagIsInGroup = $this->isInGroup($firstName, $group);
  61935. $secondTagIsInGroup = $this->isInGroup($secondName, $group);
  61936. if ($firstTagIsInGroup) {
  61937. return $secondTagIsInGroup;
  61938. }
  61939. if ($secondTagIsInGroup) {
  61940. return false;
  61941. }
  61942. }
  61943. return null;
  61944. }
  61945. private function tagName(Annotation $annotation): ?string
  61946. {
  61947. Preg::match('/@([a-zA-Z0-9_\\\-]+(?=\s|$|\())/', $annotation->getContent(), $matches);
  61948. return $matches[1] ?? null;
  61949. }
  61950. private function isInGroup(string $tag, array $group): bool
  61951. {
  61952. foreach ($group as $tagInGroup) {
  61953. $tagInGroup = str_replace('*', '\*', $tagInGroup);
  61954. $tagInGroup = preg_quote($tagInGroup, '/');
  61955. $tagInGroup = str_replace('\\\\\*', '.*?', $tagInGroup);
  61956. if (Preg::match("/^{$tagInGroup}$/", $tag)) {
  61957. return true;
  61958. }
  61959. }
  61960. return false;
  61961. }
  61962. }
  61963. <?php
  61964. declare(strict_types=1);
  61965. namespace PhpCsFixer\Fixer\Phpdoc;
  61966. use PhpCsFixer\AbstractPhpdocTypesFixer;
  61967. use PhpCsFixer\FixerDefinition\CodeSample;
  61968. use PhpCsFixer\FixerDefinition\FixerDefinition;
  61969. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  61970. use PhpCsFixer\Preg;
  61971. use PhpCsFixer\Tokenizer\Tokens;
  61972. final class PhpdocListTypeFixer extends AbstractPhpdocTypesFixer
  61973. {
  61974. public function isCandidate(Tokens $tokens): bool
  61975. {
  61976. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  61977. }
  61978. public function isRisky(): bool
  61979. {
  61980. return true;
  61981. }
  61982. public function getDefinition(): FixerDefinitionInterface
  61983. {
  61984. return new FixerDefinition(
  61985. 'PHPDoc `list` type must be used instead of `array` without a key.',
  61986. [
  61987. new CodeSample(<<<'PHP'
  61988. <?php
  61989. /**
  61990. * @param array<int> $x
  61991. * @param array<array<string>> $y
  61992. */
  61993. PHP),
  61994. ],
  61995. null,
  61996. 'Risky when `array` key should be present, but is missing.'
  61997. );
  61998. }
  61999. public function getPriority(): int
  62000. {
  62001. return 1;
  62002. }
  62003. protected function normalize(string $type): string
  62004. {
  62005. return Preg::replace('/\barray(?=<(?:[^,<]|<[^>]+>)+(>|{|\())/i', 'list', $type);
  62006. }
  62007. }
  62008. <?php
  62009. declare(strict_types=1);
  62010. namespace PhpCsFixer\Fixer\Phpdoc;
  62011. use PhpCsFixer\AbstractFixer;
  62012. use PhpCsFixer\DocBlock\DocBlock;
  62013. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  62014. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  62015. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  62016. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  62017. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  62018. use PhpCsFixer\FixerDefinition\CodeSample;
  62019. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62020. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62021. use PhpCsFixer\Tokenizer\Token;
  62022. use PhpCsFixer\Tokenizer\Tokens;
  62023. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  62024. /**
  62025. @phpstan-type
  62026. @phpstan-type
  62027. @implements
  62028. */
  62029. final class PhpdocOrderFixer extends AbstractFixer implements ConfigurableFixerInterface
  62030. {
  62031. /**
  62032. @use */
  62033. use ConfigurableFixerTrait;
  62034. /**
  62035. @const
  62036. @TODO:
  62037. */
  62038. private const ORDER_DEFAULT = ['param', 'throws', 'return'];
  62039. public function getDefinition(): FixerDefinitionInterface
  62040. {
  62041. $code = <<<'EOF'
  62042. <?php
  62043. /**
  62044. * Hello there!
  62045. *
  62046. * @throws Exception|RuntimeException foo
  62047. * @custom Test!
  62048. * @return int Return the number of changes.
  62049. * @param string $foo
  62050. * @param bool $bar Bar
  62051. */
  62052. EOF;
  62053. return new FixerDefinition(
  62054. 'Annotations in PHPDoc should be ordered in defined sequence.',
  62055. [
  62056. new CodeSample($code),
  62057. new CodeSample($code, ['order' => self::ORDER_DEFAULT]),
  62058. new CodeSample($code, ['order' => ['param', 'return', 'throws']]),
  62059. new CodeSample($code, ['order' => ['param', 'custom', 'throws', 'return']]),
  62060. ],
  62061. );
  62062. }
  62063. public function isCandidate(Tokens $tokens): bool
  62064. {
  62065. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  62066. }
  62067. public function getPriority(): int
  62068. {
  62069. return -2;
  62070. }
  62071. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  62072. {
  62073. return new FixerConfigurationResolver([
  62074. (new FixerOptionBuilder('order', 'Sequence in which annotations in PHPDoc should be ordered.'))
  62075. ->setAllowedTypes(['string[]'])
  62076. ->setAllowedValues([static function (array $order): bool {
  62077. if (\count($order) < 2) {
  62078. throw new InvalidOptionsException('The option "order" value is invalid. Minimum two tags are required.');
  62079. }
  62080. return true;
  62081. }])
  62082. ->setDefault(self::ORDER_DEFAULT)
  62083. ->getOption(),
  62084. ]);
  62085. }
  62086. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  62087. {
  62088. $configurationOrder = [];
  62089. foreach ($this->configuration['order'] as $type) {
  62090. $configurationOrder[] = $type;
  62091. $configurationOrder[] = 'phpstan-'.$type;
  62092. $configurationOrder[] = 'psalm-'.$type;
  62093. }
  62094. foreach ($tokens as $index => $token) {
  62095. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  62096. continue;
  62097. }
  62098. $content = $token->getContent();
  62099. $successors = $configurationOrder;
  62100. while (\count($successors) >= 3) {
  62101. $predecessor = array_shift($successors);
  62102. $content = $this->moveAnnotationsBefore($predecessor, $successors, $content);
  62103. }
  62104. $predecessors = $configurationOrder;
  62105. $last = array_pop($predecessors);
  62106. $content = $this->moveAnnotationsAfter($last, $predecessors, $content);
  62107. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  62108. }
  62109. }
  62110. private function moveAnnotationsBefore(string $move, array $before, string $content): string
  62111. {
  62112. $doc = new DocBlock($content);
  62113. $toBeMoved = $doc->getAnnotationsOfType($move);
  62114. if (0 === \count($toBeMoved)) {
  62115. return $content;
  62116. }
  62117. $others = $doc->getAnnotationsOfType($before);
  62118. if (0 === \count($others)) {
  62119. return $content;
  62120. }
  62121. $end = end($toBeMoved)->getEnd();
  62122. $line = $doc->getLine($end);
  62123. foreach ($others as $other) {
  62124. if ($other->getStart() < $end) {
  62125. $line->setContent($line->getContent().$other->getContent());
  62126. $other->remove();
  62127. }
  62128. }
  62129. return $doc->getContent();
  62130. }
  62131. private function moveAnnotationsAfter(string $move, array $after, string $content): string
  62132. {
  62133. $doc = new DocBlock($content);
  62134. $toBeMoved = $doc->getAnnotationsOfType($move);
  62135. if (0 === \count($toBeMoved)) {
  62136. return $content;
  62137. }
  62138. $others = $doc->getAnnotationsOfType($after);
  62139. if (0 === \count($others)) {
  62140. return $content;
  62141. }
  62142. $start = $toBeMoved[0]->getStart();
  62143. $line = $doc->getLine($start);
  62144. foreach (array_reverse($others) as $other) {
  62145. if ($other->getEnd() > $start) {
  62146. $line->setContent($other->getContent().$line->getContent());
  62147. $other->remove();
  62148. }
  62149. }
  62150. return $doc->getContent();
  62151. }
  62152. }
  62153. <?php
  62154. declare(strict_types=1);
  62155. namespace PhpCsFixer\Fixer\Phpdoc;
  62156. use PhpCsFixer\AbstractFixer;
  62157. use PhpCsFixer\FixerDefinition\CodeSample;
  62158. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62159. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62160. use PhpCsFixer\Preg;
  62161. use PhpCsFixer\Tokenizer\CT;
  62162. use PhpCsFixer\Tokenizer\Token;
  62163. use PhpCsFixer\Tokenizer\Tokens;
  62164. final class PhpdocNoUselessInheritdocFixer extends AbstractFixer
  62165. {
  62166. public function getDefinition(): FixerDefinitionInterface
  62167. {
  62168. return new FixerDefinition(
  62169. 'Classy that does not inherit must not have `@inheritdoc` tags.',
  62170. [
  62171. new CodeSample("<?php\n/** {@inheritdoc} */\nclass Sample\n{\n}\n"),
  62172. new CodeSample("<?php\nclass Sample\n{\n /**\n * @inheritdoc\n */\n public function Test()\n {\n }\n}\n"),
  62173. ]
  62174. );
  62175. }
  62176. public function getPriority(): int
  62177. {
  62178. return 6;
  62179. }
  62180. public function isCandidate(Tokens $tokens): bool
  62181. {
  62182. return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
  62183. }
  62184. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  62185. {
  62186. for ($index = 1, $count = \count($tokens) - 4; $index < $count; ++$index) {
  62187. if ($tokens[$index]->isGivenKind([T_CLASS, T_INTERFACE])) {
  62188. $index = $this->fixClassy($tokens, $index);
  62189. }
  62190. }
  62191. }
  62192. private function fixClassy(Tokens $tokens, int $index): int
  62193. {
  62194. $classOpenIndex = $tokens->getNextTokenOfKind($index, ['{']);
  62195. $classEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpenIndex);
  62196. $extendingOrImplementing = $this->isExtendingOrImplementing($tokens, $index, $classOpenIndex);
  62197. if (!$extendingOrImplementing) {
  62198. $this->fixClassyOutside($tokens, $index);
  62199. }
  62200. if (!$extendingOrImplementing && $this->isUsingTrait($tokens, $index, $classOpenIndex, $classEndIndex)) {
  62201. $extendingOrImplementing = true;
  62202. }
  62203. $this->fixClassyInside($tokens, $classOpenIndex, $classEndIndex, !$extendingOrImplementing);
  62204. return $classEndIndex;
  62205. }
  62206. private function fixClassyInside(Tokens $tokens, int $classOpenIndex, int $classEndIndex, bool $fixThisLevel): void
  62207. {
  62208. for ($i = $classOpenIndex; $i < $classEndIndex; ++$i) {
  62209. if ($tokens[$i]->isGivenKind(T_CLASS)) {
  62210. $i = $this->fixClassy($tokens, $i);
  62211. } elseif ($fixThisLevel && $tokens[$i]->isGivenKind(T_DOC_COMMENT)) {
  62212. $this->fixToken($tokens, $i);
  62213. }
  62214. }
  62215. }
  62216. private function fixClassyOutside(Tokens $tokens, int $classIndex): void
  62217. {
  62218. $previousIndex = $tokens->getPrevNonWhitespace($classIndex);
  62219. if ($tokens[$previousIndex]->isGivenKind(T_DOC_COMMENT)) {
  62220. $this->fixToken($tokens, $previousIndex);
  62221. }
  62222. }
  62223. private function fixToken(Tokens $tokens, int $tokenIndex): void
  62224. {
  62225. $count = 0;
  62226. $content = Preg::replaceCallback(
  62227. '#(\h*(?:@{*|{*\h*@)\h*inheritdoc\h*)([^}]*)((?:}*)\h*)#i',
  62228. static fn (array $matches): string => ' '.$matches[2],
  62229. $tokens[$tokenIndex]->getContent(),
  62230. -1,
  62231. $count
  62232. );
  62233. if ($count > 0) {
  62234. $tokens[$tokenIndex] = new Token([T_DOC_COMMENT, $content]);
  62235. }
  62236. }
  62237. private function isExtendingOrImplementing(Tokens $tokens, int $classIndex, int $classOpenIndex): bool
  62238. {
  62239. for ($index = $classIndex; $index < $classOpenIndex; ++$index) {
  62240. if ($tokens[$index]->isGivenKind([T_EXTENDS, T_IMPLEMENTS])) {
  62241. return true;
  62242. }
  62243. }
  62244. return false;
  62245. }
  62246. private function isUsingTrait(Tokens $tokens, int $classIndex, int $classOpenIndex, int $classCloseIndex): bool
  62247. {
  62248. if ($tokens[$classIndex]->isGivenKind(T_INTERFACE)) {
  62249. return false;
  62250. }
  62251. $useIndex = $tokens->getNextTokenOfKind($classOpenIndex, [[CT::T_USE_TRAIT]]);
  62252. return null !== $useIndex && $useIndex < $classCloseIndex;
  62253. }
  62254. }
  62255. <?php
  62256. declare(strict_types=1);
  62257. namespace PhpCsFixer\Fixer\Phpdoc;
  62258. use PhpCsFixer\AbstractFixer;
  62259. use PhpCsFixer\DocBlock\DocBlock;
  62260. use PhpCsFixer\DocBlock\Line;
  62261. use PhpCsFixer\DocBlock\TypeExpression;
  62262. use PhpCsFixer\FixerDefinition\CodeSample;
  62263. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62264. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62265. use PhpCsFixer\Preg;
  62266. use PhpCsFixer\Tokenizer\FCT;
  62267. use PhpCsFixer\Tokenizer\Token;
  62268. use PhpCsFixer\Tokenizer\Tokens;
  62269. final class PhpdocVarWithoutNameFixer extends AbstractFixer
  62270. {
  62271. private const PROPERTY_MODIFIER_KINDS = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_VAR, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  62272. public function getDefinition(): FixerDefinitionInterface
  62273. {
  62274. return new FixerDefinition(
  62275. '`@var` and `@type` annotations of classy properties should not contain the name.',
  62276. [new CodeSample('<?php
  62277. final class Foo
  62278. {
  62279. /**
  62280. * @var int $bar
  62281. */
  62282. public $bar;
  62283. /**
  62284. * @type $baz float
  62285. */
  62286. public $baz;
  62287. }
  62288. ')]
  62289. );
  62290. }
  62291. public function getPriority(): int
  62292. {
  62293. return 0;
  62294. }
  62295. public function isCandidate(Tokens $tokens): bool
  62296. {
  62297. return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT]);
  62298. }
  62299. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  62300. {
  62301. foreach ($tokens as $index => $token) {
  62302. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  62303. continue;
  62304. }
  62305. $nextIndex = $tokens->getNextMeaningfulToken($index);
  62306. if (null === $nextIndex) {
  62307. continue;
  62308. }
  62309. if ($tokens[$nextIndex]->isGivenKind(T_STATIC)) {
  62310. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  62311. }
  62312. if (!$tokens[$nextIndex]->isGivenKind(self::PROPERTY_MODIFIER_KINDS)) {
  62313. continue;
  62314. }
  62315. $doc = new DocBlock($token->getContent());
  62316. $firstLevelLines = $this->getFirstLevelLines($doc);
  62317. $annotations = $doc->getAnnotationsOfType(['type', 'var']);
  62318. foreach ($annotations as $annotation) {
  62319. if (isset($firstLevelLines[$annotation->getStart()])) {
  62320. $this->fixLine($firstLevelLines[$annotation->getStart()]);
  62321. }
  62322. }
  62323. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  62324. }
  62325. }
  62326. private function fixLine(Line $line): void
  62327. {
  62328. Preg::matchAll('/ \$'.TypeExpression::REGEX_IDENTIFIER.'(?<!\$this)/', $line->getContent(), $matches);
  62329. foreach ($matches[0] as $match) {
  62330. $line->setContent(str_replace($match, '', $line->getContent()));
  62331. }
  62332. }
  62333. private function getFirstLevelLines(DocBlock $docBlock): array
  62334. {
  62335. $nested = 0;
  62336. $lines = $docBlock->getLines();
  62337. foreach ($lines as $index => $line) {
  62338. $content = $line->getContent();
  62339. if (Preg::match('/\s*\*\s*}$/', $content)) {
  62340. --$nested;
  62341. }
  62342. if ($nested > 0) {
  62343. unset($lines[$index]);
  62344. }
  62345. if (Preg::match('/\s\{$/', $content)) {
  62346. ++$nested;
  62347. }
  62348. }
  62349. return $lines;
  62350. }
  62351. }
  62352. <?php
  62353. declare(strict_types=1);
  62354. namespace PhpCsFixer\Fixer\Phpdoc;
  62355. use PhpCsFixer\AbstractFixer;
  62356. use PhpCsFixer\DocBlock\DocBlock;
  62357. use PhpCsFixer\DocBlock\TypeExpression;
  62358. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  62359. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  62360. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  62361. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  62362. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  62363. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  62364. use PhpCsFixer\FixerDefinition\CodeSample;
  62365. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62366. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62367. use PhpCsFixer\Preg;
  62368. use PhpCsFixer\Tokenizer\Token;
  62369. use PhpCsFixer\Tokenizer\Tokens;
  62370. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  62371. /**
  62372. @phpstan-type
  62373. @phpstan-type
  62374. @implements
  62375. */
  62376. final class PhpdocAlignFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  62377. {
  62378. /**
  62379. @use */
  62380. use ConfigurableFixerTrait;
  62381. public const ALIGN_LEFT = 'left';
  62382. public const ALIGN_VERTICAL = 'vertical';
  62383. private const DEFAULT_TAGS = [
  62384. 'method',
  62385. 'param',
  62386. 'property',
  62387. 'return',
  62388. 'throws',
  62389. 'type',
  62390. 'var',
  62391. ];
  62392. private const TAGS_WITH_NAME = [
  62393. 'param',
  62394. 'property',
  62395. 'property-read',
  62396. 'property-write',
  62397. 'phpstan-param',
  62398. 'phpstan-property',
  62399. 'phpstan-property-read',
  62400. 'phpstan-property-write',
  62401. 'phpstan-assert',
  62402. 'phpstan-assert-if-true',
  62403. 'phpstan-assert-if-false',
  62404. 'psalm-param',
  62405. 'psalm-param-out',
  62406. 'psalm-property',
  62407. 'psalm-property-read',
  62408. 'psalm-property-write',
  62409. 'psalm-assert',
  62410. 'psalm-assert-if-true',
  62411. 'psalm-assert-if-false',
  62412. ];
  62413. private const TAGS_WITH_METHOD_SIGNATURE = [
  62414. 'method',
  62415. 'phpstan-method',
  62416. 'psalm-method',
  62417. ];
  62418. private const DEFAULT_SPACING = 1;
  62419. private const DEFAULT_SPACING_KEY = '_default';
  62420. private string $regex;
  62421. private string $regexCommentLine;
  62422. private string $align;
  62423. private $spacing = 1;
  62424. public function getDefinition(): FixerDefinitionInterface
  62425. {
  62426. $code = <<<'EOF'
  62427. <?php
  62428. /**
  62429. * @param EngineInterface $templating
  62430. * @param string $format
  62431. * @param int $code an HTTP response status code
  62432. * @param bool $debug
  62433. * @param mixed &$reference a parameter passed by reference
  62434. *
  62435. * @return Foo description foo
  62436. *
  62437. * @throws Foo description foo
  62438. * description foo
  62439. *
  62440. */
  62441. EOF;
  62442. return new FixerDefinition(
  62443. 'All items of the given PHPDoc tags must be either left-aligned or (by default) aligned vertically.',
  62444. [
  62445. new CodeSample($code),
  62446. new CodeSample($code, ['align' => self::ALIGN_VERTICAL]),
  62447. new CodeSample($code, ['align' => self::ALIGN_LEFT]),
  62448. new CodeSample($code, ['align' => self::ALIGN_LEFT, 'spacing' => 2]),
  62449. new CodeSample($code, ['align' => self::ALIGN_LEFT, 'spacing' => ['param' => 2]]),
  62450. ],
  62451. );
  62452. }
  62453. public function getPriority(): int
  62454. {
  62455. return -42;
  62456. }
  62457. public function isCandidate(Tokens $tokens): bool
  62458. {
  62459. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  62460. }
  62461. protected function configurePostNormalisation(): void
  62462. {
  62463. $tagsWithNameToAlign = array_intersect($this->configuration['tags'], self::TAGS_WITH_NAME);
  62464. $tagsWithMethodSignatureToAlign = array_intersect($this->configuration['tags'], self::TAGS_WITH_METHOD_SIGNATURE);
  62465. $tagsWithoutNameToAlign = array_diff($this->configuration['tags'], $tagsWithNameToAlign, $tagsWithMethodSignatureToAlign);
  62466. $indentRegex = '^(?P<indent>(?:\ {2}|\t)*)\ ?';
  62467. $types = [];
  62468. if ([] !== $tagsWithNameToAlign) {
  62469. $types[] = '(?P<tag>'.implode('|', $tagsWithNameToAlign).')\s+(?P<hint>(?:'.TypeExpression::REGEX_TYPES.')?)\s*(?P<var>(?:&|\.{3})?\$\S+)';
  62470. }
  62471. if ([] !== $tagsWithoutNameToAlign) {
  62472. $types[] = '(?P<tag2>'.implode('|', $tagsWithoutNameToAlign).')\s+(?P<hint2>(?:'.TypeExpression::REGEX_TYPES.')?)';
  62473. }
  62474. if ([] !== $tagsWithMethodSignatureToAlign) {
  62475. $types[] = '(?P<tag3>'.implode('|', $tagsWithMethodSignatureToAlign).')(\s+(?P<static>static))?(\s+(?P<hint3>(?:'.TypeExpression::REGEX_TYPES.')?))\s+(?P<signature>.+\))';
  62476. }
  62477. $desc = '(?:\s+(?P<desc>\V*))';
  62478. $this->regex = '/'.$indentRegex.'\*\h*@(?J)(?:'.implode('|', $types).')'.$desc.'\h*\r?$/';
  62479. $this->regexCommentLine = '/'.$indentRegex.'\*(?!\h?+@)(?:\s+(?P<desc>\V+))(?<!\*\/)\r?$/';
  62480. $this->align = $this->configuration['align'];
  62481. $this->spacing = $this->configuration['spacing'];
  62482. }
  62483. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  62484. {
  62485. foreach ($tokens as $index => $token) {
  62486. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  62487. continue;
  62488. }
  62489. $content = $token->getContent();
  62490. $docBlock = new DocBlock($content);
  62491. $this->fixDocBlock($docBlock);
  62492. $newContent = $docBlock->getContent();
  62493. if ($newContent !== $content) {
  62494. $tokens[$index] = new Token([T_DOC_COMMENT, $newContent]);
  62495. }
  62496. }
  62497. }
  62498. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  62499. {
  62500. $allowPositiveIntegers = static function ($value) {
  62501. $spacings = \is_array($value) ? $value : [$value];
  62502. foreach ($spacings as $val) {
  62503. if (\is_int($val) && $val <= 0) {
  62504. throw new InvalidOptionsException('The option "spacing" is invalid. All spacings must be greater than zero.');
  62505. }
  62506. }
  62507. return true;
  62508. };
  62509. $tags = new FixerOptionBuilder(
  62510. 'tags',
  62511. 'The tags that should be aligned. Allowed values are tags with name (`\''.implode('\', \'', self::TAGS_WITH_NAME).'\'`), tags with method signature (`\''.implode('\', \'', self::TAGS_WITH_METHOD_SIGNATURE).'\'`) and any custom tag with description (e.g. `@tag <desc>`).'
  62512. );
  62513. $tags
  62514. ->setAllowedTypes(['string[]'])
  62515. ->setDefault(self::DEFAULT_TAGS)
  62516. ;
  62517. $align = new FixerOptionBuilder('align', 'How comments should be aligned.');
  62518. $align
  62519. ->setAllowedTypes(['string'])
  62520. ->setAllowedValues([self::ALIGN_LEFT, self::ALIGN_VERTICAL])
  62521. ->setDefault(self::ALIGN_VERTICAL)
  62522. ;
  62523. $spacing = new FixerOptionBuilder(
  62524. 'spacing',
  62525. 'Spacing between tag, hint, comment, signature, etc. You can set same spacing for all tags using a positive integer or different spacings for different tags using an associative array of positive integers `[\'tagA\' => spacingForA, \'tagB\' => spacingForB]`. If you want to define default spacing to more than 1 space use `_default` key in config array, e.g.: `[\'tagA\' => spacingForA, \'tagB\' => spacingForB, \'_default\' => spacingForAllOthers]`.'
  62526. );
  62527. $spacing->setAllowedTypes(['int', 'array<string, int>'])
  62528. ->setAllowedValues([$allowPositiveIntegers])
  62529. ->setDefault(self::DEFAULT_SPACING)
  62530. ;
  62531. return new FixerConfigurationResolver([$tags->getOption(), $align->getOption(), $spacing->getOption()]);
  62532. }
  62533. private function fixDocBlock(DocBlock $docBlock): void
  62534. {
  62535. $lineEnding = $this->whitespacesConfig->getLineEnding();
  62536. for ($i = 0, $l = \count($docBlock->getLines()); $i < $l; ++$i) {
  62537. $matches = $this->getMatches($docBlock->getLine($i)->getContent());
  62538. if (null === $matches) {
  62539. continue;
  62540. }
  62541. $current = $i;
  62542. $items = [$matches];
  62543. while (true) {
  62544. if (null === $docBlock->getLine(++$i)) {
  62545. break 2;
  62546. }
  62547. $matches = $this->getMatches($docBlock->getLine($i)->getContent(), true);
  62548. if (null === $matches) {
  62549. break;
  62550. }
  62551. $items[] = $matches;
  62552. }
  62553. $hasStatic = false;
  62554. $tagMax = 0;
  62555. $hintMax = 0;
  62556. $varMax = 0;
  62557. foreach ($items as $item) {
  62558. if (null === $item['tag']) {
  62559. continue;
  62560. }
  62561. $hasStatic = $hasStatic || '' !== $item['static'];
  62562. $tagMax = max($tagMax, \strlen($item['tag']));
  62563. $hintMax = max($hintMax, \strlen($item['hint']));
  62564. $varMax = max($varMax, \strlen($item['var']));
  62565. }
  62566. $itemOpeningLine = null;
  62567. $currTag = null;
  62568. $spacingForTag = $this->spacingForTag($currTag);
  62569. foreach ($items as $j => $item) {
  62570. if (null === $item['tag']) {
  62571. if ('@' === $item['desc'][0]) {
  62572. $line = $item['indent'].' * '.$item['desc'];
  62573. $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
  62574. continue;
  62575. }
  62576. $extraIndent = 2 * $spacingForTag;
  62577. if (\in_array($itemOpeningLine['tag'], self::TAGS_WITH_NAME, true) || \in_array($itemOpeningLine['tag'], self::TAGS_WITH_METHOD_SIGNATURE, true)) {
  62578. $extraIndent += $varMax + $spacingForTag;
  62579. }
  62580. if ($hasStatic) {
  62581. $extraIndent += 7;
  62582. }
  62583. $line = $item['indent']
  62584. .' * '
  62585. .('' !== $itemOpeningLine['hint'] ? ' ' : '')
  62586. .$this->getIndent(
  62587. $tagMax + $hintMax + $extraIndent,
  62588. $this->getLeftAlignedDescriptionIndent($items, $j)
  62589. )
  62590. .$item['desc'];
  62591. $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
  62592. continue;
  62593. }
  62594. $currTag = $item['tag'];
  62595. $spacingForTag = $this->spacingForTag($currTag);
  62596. $itemOpeningLine = $item;
  62597. $line = $item['indent']
  62598. .' * @'
  62599. .$item['tag'];
  62600. if ($hasStatic) {
  62601. $line .= $this->getIndent(
  62602. $tagMax - \strlen($item['tag']) + $spacingForTag,
  62603. '' !== $item['static'] ? $spacingForTag : 0
  62604. )
  62605. .('' !== $item['static'] ? $item['static'] : $this->getIndent(6 , 0));
  62606. $hintVerticalAlignIndent = $spacingForTag;
  62607. } else {
  62608. $hintVerticalAlignIndent = $tagMax - \strlen($item['tag']) + $spacingForTag;
  62609. }
  62610. $line .= $this->getIndent(
  62611. $hintVerticalAlignIndent,
  62612. '' !== $item['hint'] ? $spacingForTag : 0
  62613. )
  62614. .$item['hint'];
  62615. if ('' !== $item['var']) {
  62616. $line .= $this->getIndent((0 !== $hintMax ? $hintMax : -1) - mb_strlen($item['hint']) + $spacingForTag, $spacingForTag)
  62617. .$item['var']
  62618. .(
  62619. '' !== $item['desc']
  62620. ? $this->getIndent($varMax - \strlen($item['var']) + $spacingForTag, $spacingForTag).$item['desc']
  62621. : ''
  62622. );
  62623. } elseif ('' !== $item['desc']) {
  62624. $line .= $this->getIndent($hintMax - \strlen($item['hint']) + $spacingForTag, $spacingForTag).$item['desc'];
  62625. }
  62626. $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
  62627. }
  62628. }
  62629. }
  62630. private function spacingForTag(?string $tag): int
  62631. {
  62632. return (\is_int($this->spacing))
  62633. ? $this->spacing
  62634. : ($this->spacing[$tag] ?? $this->spacing[self::DEFAULT_SPACING_KEY] ?? self::DEFAULT_SPACING);
  62635. }
  62636. private function getMatches(string $line, bool $matchCommentOnly = false): ?array
  62637. {
  62638. if (Preg::match($this->regex, $line, $matches)) {
  62639. if (isset($matches['tag2']) && '' !== $matches['tag2']) {
  62640. $matches['tag'] = $matches['tag2'];
  62641. $matches['hint'] = $matches['hint2'];
  62642. $matches['var'] = '';
  62643. }
  62644. if (isset($matches['tag3']) && '' !== $matches['tag3']) {
  62645. $matches['tag'] = $matches['tag3'];
  62646. $matches['hint'] = $matches['hint3'];
  62647. $matches['var'] = $matches['signature'];
  62648. if ('' === $matches['hint'] && '' !== $matches['static']) {
  62649. $matches['hint'] = $matches['static'];
  62650. $matches['static'] = '';
  62651. }
  62652. }
  62653. if (isset($matches['hint'])) {
  62654. $matches['hint'] = trim($matches['hint']);
  62655. }
  62656. $matches['static'] ??= '';
  62657. return $matches;
  62658. }
  62659. if ($matchCommentOnly && Preg::match($this->regexCommentLine, $line, $matches)) {
  62660. $matches['tag'] = null;
  62661. $matches['var'] = '';
  62662. $matches['hint'] = '';
  62663. $matches['static'] = '';
  62664. return $matches;
  62665. }
  62666. return null;
  62667. }
  62668. private function getIndent(int $verticalAlignIndent, int $leftAlignIndent = 1): string
  62669. {
  62670. $indent = self::ALIGN_VERTICAL === $this->align ? $verticalAlignIndent : $leftAlignIndent;
  62671. return str_repeat(' ', $indent);
  62672. }
  62673. private function getLeftAlignedDescriptionIndent(array $items, int $index): int
  62674. {
  62675. if (self::ALIGN_LEFT !== $this->align) {
  62676. return 0;
  62677. }
  62678. $item = null;
  62679. for (; $index >= 0; --$index) {
  62680. $item = $items[$index];
  62681. if (null !== $item['tag']) {
  62682. break;
  62683. }
  62684. }
  62685. if (null === $item) {
  62686. return 0;
  62687. }
  62688. $spacingForTag = $this->spacingForTag($item['tag']);
  62689. return
  62690. $this->getSentenceIndent($item['static'], $spacingForTag)
  62691. + $this->getSentenceIndent($item['tag'], $spacingForTag)
  62692. + $this->getSentenceIndent($item['hint'], $spacingForTag)
  62693. + $this->getSentenceIndent($item['var'], $spacingForTag);
  62694. }
  62695. private function getSentenceIndent(?string $sentence, int $spacingForTag = 1): int
  62696. {
  62697. if (null === $sentence) {
  62698. return 0;
  62699. }
  62700. $length = \strlen($sentence);
  62701. return 0 === $length ? 0 : $length + $spacingForTag;
  62702. }
  62703. }
  62704. <?php
  62705. declare(strict_types=1);
  62706. namespace PhpCsFixer\Fixer\Phpdoc;
  62707. use PhpCsFixer\AbstractFixer;
  62708. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  62709. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  62710. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  62711. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  62712. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  62713. use PhpCsFixer\FixerDefinition\CodeSample;
  62714. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62715. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62716. use PhpCsFixer\Preg;
  62717. use PhpCsFixer\Tokenizer\Analyzer\CommentsAnalyzer;
  62718. use PhpCsFixer\Tokenizer\Token;
  62719. use PhpCsFixer\Tokenizer\Tokens;
  62720. /**
  62721. @phpstan-type
  62722. @phpstan-type
  62723. @implements
  62724. */
  62725. final class PhpdocToCommentFixer extends AbstractFixer implements ConfigurableFixerInterface
  62726. {
  62727. /**
  62728. @use */
  62729. use ConfigurableFixerTrait;
  62730. private array $ignoredTags = [];
  62731. private bool $allowBeforeReturnStatement = false;
  62732. public function isCandidate(Tokens $tokens): bool
  62733. {
  62734. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  62735. }
  62736. public function getPriority(): int
  62737. {
  62738. return 25;
  62739. }
  62740. public function getDefinition(): FixerDefinitionInterface
  62741. {
  62742. return new FixerDefinition(
  62743. 'Docblocks should only be used on structural elements.',
  62744. [
  62745. new CodeSample(
  62746. '<?php
  62747. $first = true;// needed because by default first docblock is never fixed.
  62748. /** This should be a comment */
  62749. foreach($connections as $key => $sqlite) {
  62750. $sqlite->open($path);
  62751. }
  62752. '
  62753. ),
  62754. new CodeSample(
  62755. '<?php
  62756. $first = true;// needed because by default first docblock is never fixed.
  62757. /** This should be a comment */
  62758. foreach($connections as $key => $sqlite) {
  62759. $sqlite->open($path);
  62760. }
  62761. /** @todo This should be a PHPDoc as the tag is on "ignored_tags" list */
  62762. foreach($connections as $key => $sqlite) {
  62763. $sqlite->open($path);
  62764. }
  62765. ',
  62766. ['ignored_tags' => ['todo']]
  62767. ),
  62768. new CodeSample(
  62769. '<?php
  62770. $first = true;// needed because by default first docblock is never fixed.
  62771. /** This should be a comment */
  62772. foreach($connections as $key => $sqlite) {
  62773. $sqlite->open($path);
  62774. }
  62775. function returnClassName() {
  62776. /** @var class-string */
  62777. return \StdClass::class;
  62778. }
  62779. ',
  62780. ['allow_before_return_statement' => true]
  62781. ),
  62782. ]
  62783. );
  62784. }
  62785. protected function configurePostNormalisation(): void
  62786. {
  62787. $this->ignoredTags = array_map(
  62788. static fn (string $tag): string => strtolower($tag),
  62789. $this->configuration['ignored_tags']
  62790. );
  62791. $this->allowBeforeReturnStatement = true === $this->configuration['allow_before_return_statement'];
  62792. }
  62793. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  62794. {
  62795. return new FixerConfigurationResolver([
  62796. (new FixerOptionBuilder('ignored_tags', 'List of ignored tags (matched case insensitively).'))
  62797. ->setAllowedTypes(['string[]'])
  62798. ->setDefault([])
  62799. ->getOption(),
  62800. (new FixerOptionBuilder('allow_before_return_statement', 'Whether to allow PHPDoc before return statement.'))
  62801. ->setAllowedTypes(['bool'])
  62802. ->setDefault(false)
  62803. ->getOption(),
  62804. ]);
  62805. }
  62806. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  62807. {
  62808. $commentsAnalyzer = new CommentsAnalyzer();
  62809. foreach ($tokens as $index => $token) {
  62810. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  62811. continue;
  62812. }
  62813. if ($commentsAnalyzer->isHeaderComment($tokens, $index)) {
  62814. continue;
  62815. }
  62816. if ($this->allowBeforeReturnStatement && $commentsAnalyzer->isBeforeReturn($tokens, $index)) {
  62817. continue;
  62818. }
  62819. if ($commentsAnalyzer->isBeforeStructuralElement($tokens, $index)) {
  62820. continue;
  62821. }
  62822. if (0 < Preg::matchAll('~\@([a-zA-Z0-9_\\\-]+)\b~', $token->getContent(), $matches)) {
  62823. foreach ($matches[1] as $match) {
  62824. if (\in_array(strtolower($match), $this->ignoredTags, true)) {
  62825. continue 2;
  62826. }
  62827. }
  62828. }
  62829. $tokens[$index] = new Token([T_COMMENT, '/*'.ltrim($token->getContent(), '/*')]);
  62830. }
  62831. }
  62832. }
  62833. <?php
  62834. declare(strict_types=1);
  62835. namespace PhpCsFixer\Fixer\Phpdoc;
  62836. use PhpCsFixer\AbstractPhpdocTypesFixer;
  62837. use PhpCsFixer\FixerDefinition\CodeSample;
  62838. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62839. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62840. use PhpCsFixer\Preg;
  62841. use PhpCsFixer\Tokenizer\Tokens;
  62842. final class PhpdocArrayTypeFixer extends AbstractPhpdocTypesFixer
  62843. {
  62844. public function isCandidate(Tokens $tokens): bool
  62845. {
  62846. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  62847. }
  62848. public function isRisky(): bool
  62849. {
  62850. return true;
  62851. }
  62852. public function getDefinition(): FixerDefinitionInterface
  62853. {
  62854. return new FixerDefinition(
  62855. 'PHPDoc `array<T>` type must be used instead of `T[]`.',
  62856. [
  62857. new CodeSample(<<<'PHP'
  62858. <?php
  62859. /**
  62860. * @param int[] $x
  62861. * @param string[][] $y
  62862. */
  62863. PHP),
  62864. ],
  62865. null,
  62866. 'Risky when using `T[]` in union types.'
  62867. );
  62868. }
  62869. public function getPriority(): int
  62870. {
  62871. return 2;
  62872. }
  62873. protected function normalize(string $type): string
  62874. {
  62875. if (Preg::match('/^\??\s*[\'"]/', $type)) {
  62876. return $type;
  62877. }
  62878. $prefix = '';
  62879. if (str_starts_with($type, '?')) {
  62880. $prefix = '?';
  62881. $type = substr($type, 1);
  62882. }
  62883. return $prefix.Preg::replaceCallback(
  62884. '/^(.+?)((?:\h*\[\h*\])+)$/',
  62885. static function (array $matches): string {
  62886. $type = $matches[1];
  62887. $level = substr_count($matches[2], '[');
  62888. if (str_starts_with($type, '(') && str_ends_with($type, ')')) {
  62889. $type = substr($type, 1, -1);
  62890. }
  62891. return str_repeat('array<', $level).$type.str_repeat('>', $level);
  62892. },
  62893. $type,
  62894. );
  62895. }
  62896. }
  62897. <?php
  62898. declare(strict_types=1);
  62899. namespace PhpCsFixer\Fixer\Phpdoc;
  62900. use PhpCsFixer\AbstractFixer;
  62901. use PhpCsFixer\DocBlock\Annotation;
  62902. use PhpCsFixer\DocBlock\DocBlock;
  62903. use PhpCsFixer\DocBlock\TypeExpression;
  62904. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  62905. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  62906. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  62907. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  62908. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  62909. use PhpCsFixer\FixerDefinition\CodeSample;
  62910. use PhpCsFixer\FixerDefinition\FixerDefinition;
  62911. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  62912. use PhpCsFixer\Preg;
  62913. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  62914. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  62915. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  62916. use PhpCsFixer\Tokenizer\CT;
  62917. use PhpCsFixer\Tokenizer\FCT;
  62918. use PhpCsFixer\Tokenizer\Token;
  62919. use PhpCsFixer\Tokenizer\Tokens;
  62920. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  62921. /**
  62922. @phpstan-type
  62923. @phpstan-type
  62924. @phpstan-type
  62925. @phpstan-type
  62926. @implements
  62927. */
  62928. final class NoSuperfluousPhpdocTagsFixer extends AbstractFixer implements ConfigurableFixerInterface
  62929. {
  62930. /**
  62931. @use */
  62932. use ConfigurableFixerTrait;
  62933. private const NO_TYPE_INFO = [
  62934. 'types' => [],
  62935. 'allows_null' => true,
  62936. ];
  62937. private const SYMBOL_KINDS = [T_CLASS, T_INTERFACE, FCT::T_ENUM];
  62938. private const MODIFIER_KINDS = [
  62939. T_PRIVATE,
  62940. T_PROTECTED,
  62941. T_PUBLIC,
  62942. T_ABSTRACT,
  62943. T_FINAL,
  62944. T_STATIC,
  62945. FCT::T_READONLY,
  62946. FCT::T_PRIVATE_SET,
  62947. FCT::T_PROTECTED_SET,
  62948. FCT::T_PUBLIC_SET,
  62949. ];
  62950. public function getDefinition(): FixerDefinitionInterface
  62951. {
  62952. return new FixerDefinition(
  62953. 'Removes `@param`, `@return` and `@var` tags that don\'t provide any useful information.',
  62954. [
  62955. new CodeSample(
  62956. '<?php
  62957. class Foo {
  62958. /**
  62959. * @param Bar $bar
  62960. * @param mixed $baz
  62961. *
  62962. * @return Baz
  62963. */
  62964. public function doFoo(Bar $bar, $baz): Baz {}
  62965. }
  62966. ',
  62967. ),
  62968. new CodeSample(
  62969. '<?php
  62970. class Foo {
  62971. /**
  62972. * @param Bar $bar
  62973. * @param mixed $baz
  62974. */
  62975. public function doFoo(Bar $bar, $baz) {}
  62976. }
  62977. ',
  62978. ['allow_mixed' => true],
  62979. ),
  62980. new CodeSample(
  62981. '<?php
  62982. class Foo {
  62983. /**
  62984. * @inheritDoc
  62985. */
  62986. public function doFoo(Bar $bar, $baz) {}
  62987. }
  62988. ',
  62989. ['remove_inheritdoc' => true],
  62990. ),
  62991. new CodeSample(
  62992. '<?php
  62993. class Foo {
  62994. /**
  62995. * @param Bar $bar
  62996. * @param mixed $baz
  62997. * @param string|int|null $qux
  62998. * @param mixed $foo
  62999. */
  63000. public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
  63001. }
  63002. ',
  63003. ['allow_hidden_params' => true],
  63004. ),
  63005. new CodeSample(
  63006. '<?php
  63007. class Foo {
  63008. /**
  63009. * @param Bar $bar
  63010. * @param mixed $baz
  63011. * @param string|int|null $qux
  63012. * @param mixed $foo
  63013. */
  63014. public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
  63015. }
  63016. ',
  63017. ['allow_unused_params' => true],
  63018. ),
  63019. ]
  63020. );
  63021. }
  63022. public function getPriority(): int
  63023. {
  63024. return 6;
  63025. }
  63026. public function isCandidate(Tokens $tokens): bool
  63027. {
  63028. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  63029. }
  63030. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63031. {
  63032. $tokensAnalyzer = new TokensAnalyzer($tokens);
  63033. $namespaceUseAnalyzer = new NamespaceUsesAnalyzer();
  63034. $shortNames = [];
  63035. $currentSymbol = null;
  63036. $currentSymbolEndIndex = null;
  63037. foreach ($namespaceUseAnalyzer->getDeclarationsFromTokens($tokens) as $namespaceUseAnalysis) {
  63038. $shortNames[strtolower($namespaceUseAnalysis->getShortName())] = strtolower($namespaceUseAnalysis->getFullName());
  63039. }
  63040. foreach ($tokens as $index => $token) {
  63041. if ($index === $currentSymbolEndIndex) {
  63042. $currentSymbol = null;
  63043. $currentSymbolEndIndex = null;
  63044. continue;
  63045. }
  63046. if ($token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($index)) {
  63047. continue;
  63048. }
  63049. if ($token->isGivenKind(self::SYMBOL_KINDS)) {
  63050. $currentSymbol = $tokens[$tokens->getNextMeaningfulToken($index)]->getContent();
  63051. $currentSymbolEndIndex = $tokens->findBlockEnd(
  63052. Tokens::BLOCK_TYPE_CURLY_BRACE,
  63053. $tokens->getNextTokenOfKind($index, ['{']),
  63054. );
  63055. continue;
  63056. }
  63057. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  63058. continue;
  63059. }
  63060. $documentedElement = $this->findDocumentedElement($tokens, $index);
  63061. if (null === $documentedElement) {
  63062. continue;
  63063. }
  63064. $content = $initialContent = $token->getContent();
  63065. if (true === $this->configuration['remove_inheritdoc']) {
  63066. $content = $this->removeSuperfluousInheritDoc($content);
  63067. }
  63068. $namespace = (new NamespacesAnalyzer())->getNamespaceAt($tokens, $index)->getFullName();
  63069. if ('' === $namespace) {
  63070. $namespace = null;
  63071. }
  63072. if ('function' === $documentedElement['type']) {
  63073. $content = $this->fixFunctionDocComment($content, $tokens, $documentedElement, $namespace, $currentSymbol, $shortNames);
  63074. } elseif ('property' === $documentedElement['type']) {
  63075. $content = $this->fixPropertyDocComment($content, $tokens, $documentedElement, $namespace, $currentSymbol, $shortNames);
  63076. } elseif ('classy' === $documentedElement['type']) {
  63077. $content = $this->fixClassDocComment($content, $documentedElement);
  63078. } else {
  63079. throw new \RuntimeException('Unknown type.');
  63080. }
  63081. if ('' === $content) {
  63082. $content = '/** */';
  63083. }
  63084. if ($content !== $initialContent) {
  63085. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  63086. }
  63087. }
  63088. }
  63089. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  63090. {
  63091. return new FixerConfigurationResolver([
  63092. (new FixerOptionBuilder('allow_mixed', 'Whether type `mixed` without description is allowed (`true`) or considered superfluous (`false`).'))
  63093. ->setAllowedTypes(['bool'])
  63094. ->setDefault(false)
  63095. ->getOption(),
  63096. (new FixerOptionBuilder('remove_inheritdoc', 'Remove `@inheritDoc` tags.'))
  63097. ->setAllowedTypes(['bool'])
  63098. ->setDefault(false)
  63099. ->getOption(),
  63100. (new FixerOptionBuilder('allow_hidden_params', 'Whether `param` annotation for hidden params in method signature are allowed.'))
  63101. ->setAllowedTypes(['bool'])
  63102. ->setDefault(false)
  63103. ->getOption(),
  63104. (new FixerOptionBuilder('allow_unused_params', 'Whether `param` annotation without actual signature is allowed (`true`) or considered superfluous (`false`).'))
  63105. ->setAllowedTypes(['bool'])
  63106. ->setDefault(false)
  63107. ->getOption(),
  63108. ]);
  63109. }
  63110. private function findDocumentedElement(Tokens $tokens, int $docCommentIndex): ?array
  63111. {
  63112. $typeKinds = [
  63113. CT::T_NULLABLE_TYPE,
  63114. CT::T_ARRAY_TYPEHINT,
  63115. CT::T_TYPE_ALTERNATION,
  63116. CT::T_TYPE_INTERSECTION,
  63117. T_STRING,
  63118. T_NS_SEPARATOR,
  63119. ];
  63120. $element = [
  63121. 'modifiers' => [],
  63122. 'types' => [],
  63123. ];
  63124. $index = $tokens->getNextMeaningfulToken($docCommentIndex);
  63125. if (null !== $index && $tokens[$index]->isGivenKind(FCT::T_ATTRIBUTE)) {
  63126. do {
  63127. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  63128. $index = $tokens->getNextMeaningfulToken($index);
  63129. } while (null !== $index && $tokens[$index]->isGivenKind(T_ATTRIBUTE));
  63130. }
  63131. while (true) {
  63132. if (null === $index) {
  63133. break;
  63134. }
  63135. if ($tokens[$index]->isClassy()) {
  63136. $element['index'] = $index;
  63137. $element['type'] = 'classy';
  63138. return $element;
  63139. }
  63140. if ($tokens[$index]->isGivenKind([T_FUNCTION, T_FN])) {
  63141. $element['index'] = $index;
  63142. $element['type'] = 'function';
  63143. return $element;
  63144. }
  63145. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  63146. $element['index'] = $index;
  63147. $element['type'] = 'property';
  63148. return $element;
  63149. }
  63150. if ($tokens[$index]->isGivenKind(self::MODIFIER_KINDS)) {
  63151. $element['modifiers'][$index] = $tokens[$index];
  63152. } elseif ($tokens[$index]->isGivenKind($typeKinds)) {
  63153. $element['types'][$index] = $tokens[$index];
  63154. } else {
  63155. break;
  63156. }
  63157. $index = $tokens->getNextMeaningfulToken($index);
  63158. }
  63159. return null;
  63160. }
  63161. private function fixFunctionDocComment(
  63162. string $content,
  63163. Tokens $tokens,
  63164. array $element,
  63165. ?string $namespace,
  63166. ?string $currentSymbol,
  63167. array $shortNames
  63168. ): string {
  63169. $docBlock = new DocBlock($content);
  63170. $openingParenthesisIndex = $tokens->getNextTokenOfKind($element['index'], ['(']);
  63171. $closingParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesisIndex);
  63172. $argumentsInfo = $this->getArgumentsInfo(
  63173. $tokens,
  63174. $openingParenthesisIndex + 1,
  63175. $closingParenthesisIndex - 1
  63176. );
  63177. foreach ($docBlock->getAnnotationsOfType('param') as $annotation) {
  63178. $argumentName = $annotation->getVariableName();
  63179. if (null === $argumentName) {
  63180. if ($this->annotationIsSuperfluous($annotation, self::NO_TYPE_INFO, $namespace, $currentSymbol, $shortNames)) {
  63181. $annotation->remove();
  63182. }
  63183. continue;
  63184. }
  63185. if (!isset($argumentsInfo[$argumentName]) && true === $this->configuration['allow_unused_params']) {
  63186. continue;
  63187. }
  63188. if (!isset($argumentsInfo[$argumentName]) || $this->annotationIsSuperfluous($annotation, $argumentsInfo[$argumentName], $namespace, $currentSymbol, $shortNames)) {
  63189. $annotation->remove();
  63190. }
  63191. }
  63192. $returnTypeInfo = $this->getReturnTypeInfo($tokens, $closingParenthesisIndex);
  63193. foreach ($docBlock->getAnnotationsOfType('return') as $annotation) {
  63194. if ($this->annotationIsSuperfluous($annotation, $returnTypeInfo, $namespace, $currentSymbol, $shortNames)) {
  63195. $annotation->remove();
  63196. }
  63197. }
  63198. $this->removeSuperfluousModifierAnnotation($docBlock, $element);
  63199. return $docBlock->getContent();
  63200. }
  63201. private function fixPropertyDocComment(
  63202. string $content,
  63203. Tokens $tokens,
  63204. array $element,
  63205. ?string $namespace,
  63206. ?string $currentSymbol,
  63207. array $shortNames
  63208. ): string {
  63209. if (\count($element['types']) > 0) {
  63210. $propertyTypeInfo = $this->parseTypeHint($tokens, array_key_first($element['types']));
  63211. } else {
  63212. $propertyTypeInfo = self::NO_TYPE_INFO;
  63213. }
  63214. $docBlock = new DocBlock($content);
  63215. foreach ($docBlock->getAnnotationsOfType('var') as $annotation) {
  63216. if ($this->annotationIsSuperfluous($annotation, $propertyTypeInfo, $namespace, $currentSymbol, $shortNames)) {
  63217. $annotation->remove();
  63218. }
  63219. }
  63220. return $docBlock->getContent();
  63221. }
  63222. private function fixClassDocComment(string $content, array $element): string
  63223. {
  63224. $docBlock = new DocBlock($content);
  63225. $this->removeSuperfluousModifierAnnotation($docBlock, $element);
  63226. return $docBlock->getContent();
  63227. }
  63228. private function getArgumentsInfo(Tokens $tokens, int $start, int $end): array
  63229. {
  63230. $argumentsInfo = [];
  63231. for ($index = $start; $index <= $end; ++$index) {
  63232. $token = $tokens[$index];
  63233. if (!$token->isGivenKind(T_VARIABLE)) {
  63234. continue;
  63235. }
  63236. $beforeArgumentIndex = $tokens->getPrevTokenOfKind($index, ['(', ',', [CT::T_ATTRIBUTE_CLOSE]]);
  63237. $typeIndex = $tokens->getNextMeaningfulToken($beforeArgumentIndex);
  63238. if ($typeIndex !== $index) {
  63239. $info = $this->parseTypeHint($tokens, $typeIndex);
  63240. } else {
  63241. $info = self::NO_TYPE_INFO;
  63242. }
  63243. if (!$info['allows_null']) {
  63244. $nextIndex = $tokens->getNextMeaningfulToken($index);
  63245. if (
  63246. $tokens[$nextIndex]->equals('=')
  63247. && $tokens[$tokens->getNextMeaningfulToken($nextIndex)]->equals([T_STRING, 'null'], false)
  63248. ) {
  63249. $info['allows_null'] = true;
  63250. }
  63251. }
  63252. $argumentsInfo[$token->getContent()] = $info;
  63253. }
  63254. if (true === $this->configuration['allow_hidden_params']) {
  63255. $paramsString = $tokens->generatePartialCode($start, $end);
  63256. Preg::matchAll('|/\*[^$]*(\$\w+)[^*]*\*/|', $paramsString, $matches);
  63257. foreach ($matches[1] as $match) {
  63258. $argumentsInfo[$match] = self::NO_TYPE_INFO;
  63259. }
  63260. }
  63261. return $argumentsInfo;
  63262. }
  63263. private function getReturnTypeInfo(Tokens $tokens, int $closingParenthesisIndex): array
  63264. {
  63265. $colonIndex = $tokens->getNextMeaningfulToken($closingParenthesisIndex);
  63266. return $tokens[$colonIndex]->isGivenKind(CT::T_TYPE_COLON)
  63267. ? $this->parseTypeHint($tokens, $tokens->getNextMeaningfulToken($colonIndex))
  63268. : self::NO_TYPE_INFO;
  63269. }
  63270. private function parseTypeHint(Tokens $tokens, int $index): array
  63271. {
  63272. $allowsNull = false;
  63273. $types = [];
  63274. while (true) {
  63275. $type = '';
  63276. if ($tokens[$index]->isGivenKind([FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET])) {
  63277. $index = $tokens->getNextMeaningfulToken($index);
  63278. }
  63279. if ($tokens[$index]->isGivenKind([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE])) {
  63280. $index = $tokens->getNextMeaningfulToken($index);
  63281. continue;
  63282. }
  63283. if ($tokens[$index]->isGivenKind(CT::T_NULLABLE_TYPE)) {
  63284. $allowsNull = true;
  63285. $index = $tokens->getNextMeaningfulToken($index);
  63286. }
  63287. while ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STATIC, T_STRING, CT::T_ARRAY_TYPEHINT, T_CALLABLE])) {
  63288. $type .= $tokens[$index]->getContent();
  63289. $index = $tokens->getNextMeaningfulToken($index);
  63290. }
  63291. if ('' === $type) {
  63292. break;
  63293. }
  63294. $types[] = $type;
  63295. if (!$tokens[$index]->isGivenKind([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION])) {
  63296. break;
  63297. }
  63298. $index = $tokens->getNextMeaningfulToken($index);
  63299. }
  63300. return [
  63301. 'types' => $types,
  63302. 'allows_null' => $allowsNull,
  63303. ];
  63304. }
  63305. private function annotationIsSuperfluous(
  63306. Annotation $annotation,
  63307. array $info,
  63308. ?string $namespace,
  63309. ?string $currentSymbol,
  63310. array $symbolShortNames
  63311. ): bool {
  63312. if ('param' === $annotation->getTag()->getName()) {
  63313. $regex = '{\*\h*@param(?:\h+'.TypeExpression::REGEX_TYPES.')?(?!\S)(?:\h+(?:\&\h*)?(?:\.{3}\h*)?\$\S+)?(?:\s+(?<description>(?!\*+\/)\S+))?}s';
  63314. } elseif ('var' === $annotation->getTag()->getName()) {
  63315. $regex = '{\*\h*@var(?:\h+'.TypeExpression::REGEX_TYPES.')?(?!\S)(?:\h+\$\S+)?(?:\s+(?<description>(?!\*\/)\S+))?}s';
  63316. } else {
  63317. $regex = '{\*\h*@return(?:\h+'.TypeExpression::REGEX_TYPES.')?(?!\S)(?:\s+(?<description>(?!\*\/)\S+))?}s';
  63318. }
  63319. if (!Preg::match($regex, $annotation->getContent(), $matches)) {
  63320. return false;
  63321. }
  63322. if (isset($matches['description'])) {
  63323. return false;
  63324. }
  63325. if (!isset($matches['types']) || '' === $matches['types']) {
  63326. return true;
  63327. }
  63328. $annotationTypes = $this->toComparableNames($annotation->getTypes(), $namespace, $currentSymbol, $symbolShortNames);
  63329. if (['null'] === $annotationTypes && ['null'] !== $info['types']) {
  63330. return false;
  63331. }
  63332. if (['mixed'] === $annotationTypes && [] === $info['types']) {
  63333. return false === $this->configuration['allow_mixed'];
  63334. }
  63335. $actualTypes = $info['types'];
  63336. if ($info['allows_null']) {
  63337. $actualTypes[] = 'null';
  63338. }
  63339. $actualTypes = $this->toComparableNames($actualTypes, $namespace, $currentSymbol, $symbolShortNames);
  63340. if ($annotationTypes === $actualTypes) {
  63341. return true;
  63342. }
  63343. $annotationTypes = array_merge($annotationTypes, ['null']);
  63344. sort($annotationTypes);
  63345. return $actualTypes === $annotationTypes;
  63346. }
  63347. private function toComparableNames(array $types, ?string $namespace, ?string $currentSymbol, array $symbolShortNames): array
  63348. {
  63349. if (isset($types[0][0]) && '?' === $types[0][0]) {
  63350. $types = [
  63351. substr($types[0], 1),
  63352. 'null',
  63353. ];
  63354. }
  63355. $normalized = array_map(
  63356. function (string $type) use ($namespace, $currentSymbol, $symbolShortNames): string {
  63357. if (str_contains($type, '&')) {
  63358. $intersects = explode('&', $type);
  63359. $intersects = $this->toComparableNames($intersects, $namespace, $currentSymbol, $symbolShortNames);
  63360. return implode('&', $intersects);
  63361. }
  63362. if ('self' === $type && null !== $currentSymbol) {
  63363. $type = $currentSymbol;
  63364. }
  63365. $type = strtolower($type);
  63366. if (isset($symbolShortNames[$type])) {
  63367. return $symbolShortNames[$type];
  63368. }
  63369. if (str_starts_with($type, '\\')) {
  63370. return substr($type, 1);
  63371. }
  63372. if (null !== $namespace && !(new TypeAnalysis($type))->isReservedType()) {
  63373. $type = strtolower($namespace).'\\'.$type;
  63374. }
  63375. return $type;
  63376. },
  63377. $types
  63378. );
  63379. sort($normalized);
  63380. return $normalized;
  63381. }
  63382. private function removeSuperfluousInheritDoc(string $docComment): string
  63383. {
  63384. return Preg::replace('~
  63385. # $1: before @inheritDoc tag
  63386. (
  63387. # beginning of comment or a PHPDoc tag
  63388. (?:
  63389. ^/\*\*
  63390. (?:
  63391. \R
  63392. [ \t]*(?:\*[ \t]*)?
  63393. )*?
  63394. |
  63395. @\N+
  63396. )
  63397. # empty comment lines
  63398. (?:
  63399. \R
  63400. [ \t]*(?:\*[ \t]*?)?
  63401. )*
  63402. )
  63403. # spaces before @inheritDoc tag
  63404. [ \t]*
  63405. # @inheritDoc tag
  63406. (?:@inheritDocs?|\{@inheritDocs?\})
  63407. # $2: after @inheritDoc tag
  63408. (
  63409. # empty comment lines
  63410. (?:
  63411. \R
  63412. [ \t]*(?:\*[ \t]*)?
  63413. )*
  63414. # a PHPDoc tag or end of comment
  63415. (?:
  63416. @\N+
  63417. |
  63418. (?:
  63419. \R
  63420. [ \t]*(?:\*[ \t]*)?
  63421. )*
  63422. [ \t]*\*/$
  63423. )
  63424. )
  63425. ~ix', '$1$2', $docComment);
  63426. }
  63427. private function removeSuperfluousModifierAnnotation(DocBlock $docBlock, array $element): void
  63428. {
  63429. foreach (['abstract' => T_ABSTRACT, 'final' => T_FINAL] as $annotationType => $modifierToken) {
  63430. $annotations = $docBlock->getAnnotationsOfType($annotationType);
  63431. foreach ($element['modifiers'] as $token) {
  63432. if ($token->isGivenKind($modifierToken)) {
  63433. foreach ($annotations as $annotation) {
  63434. $annotation->remove();
  63435. }
  63436. }
  63437. }
  63438. }
  63439. }
  63440. }
  63441. <?php
  63442. declare(strict_types=1);
  63443. namespace PhpCsFixer\Fixer\Phpdoc;
  63444. use PhpCsFixer\AbstractFixer;
  63445. use PhpCsFixer\FixerDefinition\CodeSample;
  63446. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63447. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63448. use PhpCsFixer\Preg;
  63449. use PhpCsFixer\Tokenizer\Token;
  63450. use PhpCsFixer\Tokenizer\Tokens;
  63451. use PhpCsFixer\Utils;
  63452. final class PhpdocIndentFixer extends AbstractFixer
  63453. {
  63454. public function getDefinition(): FixerDefinitionInterface
  63455. {
  63456. return new FixerDefinition(
  63457. 'Docblocks should have the same indentation as the documented subject.',
  63458. [new CodeSample('<?php
  63459. class DocBlocks
  63460. {
  63461. /**
  63462. * Test constants
  63463. */
  63464. const INDENT = 1;
  63465. }
  63466. ')]
  63467. );
  63468. }
  63469. public function getPriority(): int
  63470. {
  63471. return 20;
  63472. }
  63473. public function isCandidate(Tokens $tokens): bool
  63474. {
  63475. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  63476. }
  63477. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63478. {
  63479. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  63480. $token = $tokens[$index];
  63481. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  63482. continue;
  63483. }
  63484. $nextIndex = $tokens->getNextMeaningfulToken($index);
  63485. if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
  63486. continue;
  63487. }
  63488. $prevIndex = $index - 1;
  63489. $prevToken = $tokens[$prevIndex];
  63490. if (
  63491. $prevToken->isGivenKind(T_OPEN_TAG)
  63492. || ($prevToken->isWhitespace(" \t") && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG))
  63493. || $prevToken->equalsAny([';', ',', '{', '('])
  63494. ) {
  63495. continue;
  63496. }
  63497. if ($tokens[$nextIndex - 1]->isWhitespace()) {
  63498. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]);
  63499. } else {
  63500. $indent = '';
  63501. }
  63502. $newPrevContent = $this->fixWhitespaceBeforeDocblock($prevToken->getContent(), $indent);
  63503. $tokens[$index] = new Token([T_DOC_COMMENT, $this->fixDocBlock($token->getContent(), $indent)]);
  63504. if (!$prevToken->isWhitespace()) {
  63505. if ('' !== $indent) {
  63506. $tokens->insertAt($index, new Token([T_WHITESPACE, $indent]));
  63507. }
  63508. } elseif ('' !== $newPrevContent) {
  63509. if ($prevToken->isArray()) {
  63510. $tokens[$prevIndex] = new Token([$prevToken->getId(), $newPrevContent]);
  63511. } else {
  63512. $tokens[$prevIndex] = new Token($newPrevContent);
  63513. }
  63514. } else {
  63515. $tokens->clearAt($prevIndex);
  63516. }
  63517. }
  63518. }
  63519. private function fixDocBlock(string $content, string $indent): string
  63520. {
  63521. return ltrim(Preg::replace('/^\h*\*/m', $indent.' *', $content));
  63522. }
  63523. private function fixWhitespaceBeforeDocblock(string $content, string $indent): string
  63524. {
  63525. return rtrim($content, " \t").$indent;
  63526. }
  63527. }
  63528. <?php
  63529. declare(strict_types=1);
  63530. namespace PhpCsFixer\Fixer\Phpdoc;
  63531. use PhpCsFixer\AbstractFixer;
  63532. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  63533. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  63534. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  63535. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  63536. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  63537. use PhpCsFixer\FixerDefinition\CodeSample;
  63538. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63539. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63540. use PhpCsFixer\Preg;
  63541. use PhpCsFixer\Tokenizer\Token;
  63542. use PhpCsFixer\Tokenizer\Tokens;
  63543. /**
  63544. @phpstan-type
  63545. @phpstan-type
  63546. @implements
  63547. */
  63548. final class PhpdocInlineTagNormalizerFixer extends AbstractFixer implements ConfigurableFixerInterface
  63549. {
  63550. /**
  63551. @use */
  63552. use ConfigurableFixerTrait;
  63553. public function isCandidate(Tokens $tokens): bool
  63554. {
  63555. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  63556. }
  63557. public function getDefinition(): FixerDefinitionInterface
  63558. {
  63559. return new FixerDefinition(
  63560. 'Fixes PHPDoc inline tags.',
  63561. [
  63562. new CodeSample(
  63563. "<?php\n/**\n * @{TUTORIAL}\n * {{ @link }}\n * @inheritDoc\n */\n"
  63564. ),
  63565. new CodeSample(
  63566. "<?php\n/**\n * @{TUTORIAL}\n * {{ @link }}\n * @inheritDoc\n */\n",
  63567. ['tags' => ['TUTORIAL']]
  63568. ),
  63569. ]
  63570. );
  63571. }
  63572. public function getPriority(): int
  63573. {
  63574. return 0;
  63575. }
  63576. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63577. {
  63578. if (0 === \count($this->configuration['tags'])) {
  63579. return;
  63580. }
  63581. foreach ($tokens as $index => $token) {
  63582. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  63583. continue;
  63584. }
  63585. $content = Preg::replaceCallback(
  63586. \sprintf(
  63587. '#(?:@{+|{+\h*@)\h*(%s)\b([^}]*)(?:}+)#i',
  63588. implode('|', array_map(static fn (string $tag): string => preg_quote($tag, '/'), $this->configuration['tags']))
  63589. ),
  63590. static function (array $matches): string {
  63591. $doc = trim($matches[2]);
  63592. if ('' === $doc) {
  63593. return '{@'.$matches[1].'}';
  63594. }
  63595. return '{@'.$matches[1].' '.$doc.'}';
  63596. },
  63597. $token->getContent()
  63598. );
  63599. $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
  63600. }
  63601. }
  63602. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  63603. {
  63604. return new FixerConfigurationResolver([
  63605. (new FixerOptionBuilder('tags', 'The list of tags to normalize.'))
  63606. ->setAllowedTypes(['string[]'])
  63607. ->setDefault(['example', 'id', 'internal', 'inheritdoc', 'inheritdocs', 'link', 'source', 'toc', 'tutorial'])
  63608. ->getOption(),
  63609. ]);
  63610. }
  63611. }
  63612. <?php
  63613. declare(strict_types=1);
  63614. namespace PhpCsFixer\Fixer\ClassUsage;
  63615. use PhpCsFixer\AbstractFixer;
  63616. use PhpCsFixer\FixerDefinition\CodeSample;
  63617. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63618. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63619. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  63620. use PhpCsFixer\Tokenizer\Token;
  63621. use PhpCsFixer\Tokenizer\Tokens;
  63622. final class DateTimeImmutableFixer extends AbstractFixer
  63623. {
  63624. public function getDefinition(): FixerDefinitionInterface
  63625. {
  63626. return new FixerDefinition(
  63627. 'Class `DateTimeImmutable` should be used instead of `DateTime`.',
  63628. [new CodeSample("<?php\nnew DateTime();\n")],
  63629. null,
  63630. 'Risky when the code relies on modifying `DateTime` objects or if any of the `date_create*` functions are overridden.'
  63631. );
  63632. }
  63633. public function isCandidate(Tokens $tokens): bool
  63634. {
  63635. return $tokens->isTokenKindFound(T_STRING);
  63636. }
  63637. public function isRisky(): bool
  63638. {
  63639. return true;
  63640. }
  63641. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63642. {
  63643. $functionsAnalyzer = new FunctionsAnalyzer();
  63644. $functionMap = [
  63645. 'date_create' => 'date_create_immutable',
  63646. 'date_create_from_format' => 'date_create_immutable_from_format',
  63647. ];
  63648. $isInNamespace = false;
  63649. $isImported = false;
  63650. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  63651. $token = $tokens[$index];
  63652. if ($token->isGivenKind(T_NAMESPACE)) {
  63653. $isInNamespace = true;
  63654. continue;
  63655. }
  63656. if ($isInNamespace && $token->isGivenKind(T_USE)) {
  63657. $nextIndex = $tokens->getNextMeaningfulToken($index);
  63658. if ('datetime' !== strtolower($tokens[$nextIndex]->getContent())) {
  63659. continue;
  63660. }
  63661. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  63662. if ($tokens[$nextNextIndex]->equals(';')) {
  63663. $isImported = true;
  63664. }
  63665. $index = $nextNextIndex;
  63666. continue;
  63667. }
  63668. if (!$token->isGivenKind(T_STRING)) {
  63669. continue;
  63670. }
  63671. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  63672. if ($tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
  63673. continue;
  63674. }
  63675. $lowercaseContent = strtolower($token->getContent());
  63676. if ('datetime' === $lowercaseContent) {
  63677. $this->fixClassUsage($tokens, $index, $isInNamespace, $isImported);
  63678. $limit = $tokens->count();
  63679. continue;
  63680. }
  63681. if (isset($functionMap[$lowercaseContent]) && $functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  63682. $tokens[$index] = new Token([T_STRING, $functionMap[$lowercaseContent]]);
  63683. }
  63684. }
  63685. }
  63686. private function fixClassUsage(Tokens $tokens, int $index, bool $isInNamespace, bool $isImported): void
  63687. {
  63688. $nextIndex = $tokens->getNextMeaningfulToken($index);
  63689. if ($tokens[$nextIndex]->isGivenKind(T_DOUBLE_COLON)) {
  63690. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  63691. if ($tokens[$nextNextIndex]->isGivenKind(T_STRING)) {
  63692. $nextNextNextIndex = $tokens->getNextMeaningfulToken($nextNextIndex);
  63693. if (!$tokens[$nextNextNextIndex]->equals('(')) {
  63694. return;
  63695. }
  63696. }
  63697. }
  63698. $isUsedAlone = false;
  63699. $isUsedWithLeadingBackslash = false;
  63700. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  63701. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  63702. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  63703. if (!$tokens[$prevPrevIndex]->isGivenKind(T_STRING)) {
  63704. $isUsedWithLeadingBackslash = true;
  63705. }
  63706. } elseif (!$tokens[$prevIndex]->isGivenKind(T_DOUBLE_COLON) && !$tokens[$prevIndex]->isObjectOperator()) {
  63707. $isUsedAlone = true;
  63708. }
  63709. if ($isUsedWithLeadingBackslash || $isUsedAlone && ($isInNamespace && $isImported || !$isInNamespace)) {
  63710. $tokens[$index] = new Token([T_STRING, \DateTimeImmutable::class]);
  63711. if ($isInNamespace && $isUsedAlone) {
  63712. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  63713. }
  63714. }
  63715. }
  63716. }
  63717. <?php
  63718. declare(strict_types=1);
  63719. namespace PhpCsFixer\Fixer;
  63720. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63721. use PhpCsFixer\Tokenizer\Tokens;
  63722. interface FixerInterface
  63723. {
  63724. public function isCandidate(Tokens $tokens): bool;
  63725. public function isRisky(): bool;
  63726. public function fix(\SplFileInfo $file, Tokens $tokens): void;
  63727. public function getDefinition(): FixerDefinitionInterface;
  63728. public function getName(): string;
  63729. public function getPriority(): int;
  63730. public function supports(\SplFileInfo $file): bool;
  63731. }
  63732. <?php
  63733. declare(strict_types=1);
  63734. namespace PhpCsFixer\Fixer\LanguageConstruct;
  63735. use PhpCsFixer\AbstractFixer;
  63736. use PhpCsFixer\FixerDefinition\CodeSample;
  63737. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63738. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63739. use PhpCsFixer\Tokenizer\Token;
  63740. use PhpCsFixer\Tokenizer\Tokens;
  63741. final class CombineConsecutiveIssetsFixer extends AbstractFixer
  63742. {
  63743. public function getDefinition(): FixerDefinitionInterface
  63744. {
  63745. return new FixerDefinition(
  63746. 'Using `isset($var) &&` multiple times should be done in one call.',
  63747. [new CodeSample("<?php\n\$a = isset(\$a) && isset(\$b);\n")]
  63748. );
  63749. }
  63750. public function getPriority(): int
  63751. {
  63752. return 4;
  63753. }
  63754. public function isCandidate(Tokens $tokens): bool
  63755. {
  63756. return $tokens->isAllTokenKindsFound([T_ISSET, T_BOOLEAN_AND]);
  63757. }
  63758. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63759. {
  63760. $tokenCount = $tokens->count();
  63761. for ($index = 1; $index < $tokenCount; ++$index) {
  63762. if (!$tokens[$index]->isGivenKind(T_ISSET)
  63763. || !$tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['(', '{', ';', '=', [T_OPEN_TAG], [T_BOOLEAN_AND], [T_BOOLEAN_OR]])) {
  63764. continue;
  63765. }
  63766. $issetInfo = $this->getIssetInfo($tokens, $index);
  63767. $issetCloseBraceIndex = end($issetInfo);
  63768. $insertLocation = prev($issetInfo) + 1;
  63769. $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);
  63770. while ($tokens[$booleanAndTokenIndex]->isGivenKind(T_BOOLEAN_AND)) {
  63771. $issetIndex = $tokens->getNextMeaningfulToken($booleanAndTokenIndex);
  63772. if (!$tokens[$issetIndex]->isGivenKind(T_ISSET)) {
  63773. $index = $issetIndex;
  63774. break;
  63775. }
  63776. $nextIssetInfo = $this->getIssetInfo($tokens, $issetIndex);
  63777. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken(end($nextIssetInfo));
  63778. $nextMeaningfulToken = $tokens[$nextMeaningfulTokenIndex];
  63779. if (!$nextMeaningfulToken->equalsAny([')', '}', ';', [T_CLOSE_TAG], [T_BOOLEAN_AND], [T_BOOLEAN_OR]])) {
  63780. $index = $nextMeaningfulTokenIndex;
  63781. break;
  63782. }
  63783. $clones = $this->getTokenClones($tokens, \array_slice($nextIssetInfo, 1, -1));
  63784. $this->clearTokens($tokens, array_merge($nextIssetInfo, [$issetIndex, $booleanAndTokenIndex]));
  63785. array_unshift($clones, new Token(','), new Token([T_WHITESPACE, ' ']));
  63786. $tokens->insertAt($insertLocation, $clones);
  63787. $numberOfTokensInserted = \count($clones);
  63788. $tokenCount += $numberOfTokensInserted;
  63789. $issetCloseBraceIndex += $numberOfTokensInserted;
  63790. $insertLocation += $numberOfTokensInserted;
  63791. $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);
  63792. }
  63793. }
  63794. }
  63795. private function clearTokens(Tokens $tokens, array $indices): void
  63796. {
  63797. foreach ($indices as $index) {
  63798. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  63799. }
  63800. }
  63801. private function getIssetInfo(Tokens $tokens, int $index): array
  63802. {
  63803. $openIndex = $tokens->getNextMeaningfulToken($index);
  63804. $braceOpenCount = 1;
  63805. $meaningfulTokenIndices = [$openIndex];
  63806. for ($i = $openIndex + 1;; ++$i) {
  63807. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  63808. continue;
  63809. }
  63810. $meaningfulTokenIndices[] = $i;
  63811. if ($tokens[$i]->equals(')')) {
  63812. --$braceOpenCount;
  63813. if (0 === $braceOpenCount) {
  63814. break;
  63815. }
  63816. } elseif ($tokens[$i]->equals('(')) {
  63817. ++$braceOpenCount;
  63818. }
  63819. }
  63820. return $meaningfulTokenIndices;
  63821. }
  63822. private function getTokenClones(Tokens $tokens, array $indices): array
  63823. {
  63824. $clones = [];
  63825. foreach ($indices as $i) {
  63826. $clones[] = clone $tokens[$i];
  63827. }
  63828. return $clones;
  63829. }
  63830. }
  63831. <?php
  63832. declare(strict_types=1);
  63833. namespace PhpCsFixer\Fixer\LanguageConstruct;
  63834. use PhpCsFixer\AbstractFixer;
  63835. use PhpCsFixer\FixerDefinition\CodeSample;
  63836. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63837. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63838. use PhpCsFixer\Tokenizer\CT;
  63839. use PhpCsFixer\Tokenizer\Token;
  63840. use PhpCsFixer\Tokenizer\Tokens;
  63841. final class ExplicitIndirectVariableFixer extends AbstractFixer
  63842. {
  63843. public function getDefinition(): FixerDefinitionInterface
  63844. {
  63845. return new FixerDefinition(
  63846. 'Add curly braces to indirect variables to make them clear to understand.',
  63847. [
  63848. new CodeSample(
  63849. <<<'EOT'
  63850. <?php
  63851. echo $$foo;
  63852. echo $$foo['bar'];
  63853. echo $foo->$bar['baz'];
  63854. echo $foo->$callback($baz);
  63855. EOT
  63856. ),
  63857. ]
  63858. );
  63859. }
  63860. public function isCandidate(Tokens $tokens): bool
  63861. {
  63862. return $tokens->isTokenKindFound(T_VARIABLE);
  63863. }
  63864. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63865. {
  63866. for ($index = $tokens->count() - 1; $index > 1; --$index) {
  63867. $token = $tokens[$index];
  63868. if (!$token->isGivenKind(T_VARIABLE)) {
  63869. continue;
  63870. }
  63871. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  63872. $prevToken = $tokens[$prevIndex];
  63873. if (!$prevToken->equals('$') && !$prevToken->isObjectOperator()) {
  63874. continue;
  63875. }
  63876. $openingBrace = CT::T_DYNAMIC_VAR_BRACE_OPEN;
  63877. $closingBrace = CT::T_DYNAMIC_VAR_BRACE_CLOSE;
  63878. if ($prevToken->isObjectOperator()) {
  63879. $openingBrace = CT::T_DYNAMIC_PROP_BRACE_OPEN;
  63880. $closingBrace = CT::T_DYNAMIC_PROP_BRACE_CLOSE;
  63881. }
  63882. $tokens->overrideRange($index, $index, [
  63883. new Token([$openingBrace, '{']),
  63884. new Token([T_VARIABLE, $token->getContent()]),
  63885. new Token([$closingBrace, '}']),
  63886. ]);
  63887. }
  63888. }
  63889. }
  63890. <?php
  63891. declare(strict_types=1);
  63892. namespace PhpCsFixer\Fixer\LanguageConstruct;
  63893. use PhpCsFixer\AbstractFixer;
  63894. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  63895. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  63896. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  63897. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  63898. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  63899. use PhpCsFixer\FixerDefinition\CodeSample;
  63900. use PhpCsFixer\FixerDefinition\FixerDefinition;
  63901. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  63902. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  63903. use PhpCsFixer\Tokenizer\Token;
  63904. use PhpCsFixer\Tokenizer\Tokens;
  63905. /**
  63906. @phpstan-type
  63907. @phpstan-type
  63908. @implements
  63909. */
  63910. final class ErrorSuppressionFixer extends AbstractFixer implements ConfigurableFixerInterface
  63911. {
  63912. /**
  63913. @use */
  63914. use ConfigurableFixerTrait;
  63915. public const OPTION_MUTE_DEPRECATION_ERROR = 'mute_deprecation_error';
  63916. public const OPTION_NOISE_REMAINING_USAGES = 'noise_remaining_usages';
  63917. public const OPTION_NOISE_REMAINING_USAGES_EXCLUDE = 'noise_remaining_usages_exclude';
  63918. public function getDefinition(): FixerDefinitionInterface
  63919. {
  63920. return new FixerDefinition(
  63921. 'Error control operator should be added to deprecation notices and/or removed from other cases.',
  63922. [
  63923. new CodeSample("<?php\ntrigger_error('Warning.', E_USER_DEPRECATED);\n"),
  63924. new CodeSample(
  63925. "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
  63926. [self::OPTION_NOISE_REMAINING_USAGES => true]
  63927. ),
  63928. new CodeSample(
  63929. "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
  63930. [
  63931. self::OPTION_NOISE_REMAINING_USAGES => true,
  63932. self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE => ['unlink'],
  63933. ]
  63934. ),
  63935. ],
  63936. null,
  63937. 'Risky because adding/removing `@` might cause changes to code behaviour or if `trigger_error` function is overridden.'
  63938. );
  63939. }
  63940. public function isCandidate(Tokens $tokens): bool
  63941. {
  63942. return $tokens->isTokenKindFound(T_STRING);
  63943. }
  63944. public function isRisky(): bool
  63945. {
  63946. return true;
  63947. }
  63948. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  63949. {
  63950. return new FixerConfigurationResolver([
  63951. (new FixerOptionBuilder(self::OPTION_MUTE_DEPRECATION_ERROR, 'Whether to add `@` in deprecation notices.'))
  63952. ->setAllowedTypes(['bool'])
  63953. ->setDefault(true)
  63954. ->getOption(),
  63955. (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES, 'Whether to remove `@` in remaining usages.'))
  63956. ->setAllowedTypes(['bool'])
  63957. ->setDefault(false)
  63958. ->getOption(),
  63959. (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE, 'List of global functions to exclude from removing `@`.'))
  63960. ->setAllowedTypes(['string[]'])
  63961. ->setDefault([])
  63962. ->getOption(),
  63963. ]);
  63964. }
  63965. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  63966. {
  63967. $functionsAnalyzer = new FunctionsAnalyzer();
  63968. $excludedFunctions = array_map(static fn (string $function): string => strtolower($function), $this->configuration[self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE]);
  63969. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  63970. $token = $tokens[$index];
  63971. if (true === $this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && $token->equals('@')) {
  63972. $tokens->clearAt($index);
  63973. continue;
  63974. }
  63975. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  63976. continue;
  63977. }
  63978. $functionIndex = $index;
  63979. $startIndex = $index;
  63980. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  63981. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  63982. $startIndex = $prevIndex;
  63983. $prevIndex = $tokens->getPrevMeaningfulToken($startIndex);
  63984. }
  63985. $index = $prevIndex;
  63986. if ($this->isDeprecationErrorCall($tokens, $functionIndex)) {
  63987. if (false === $this->configuration[self::OPTION_MUTE_DEPRECATION_ERROR]) {
  63988. continue;
  63989. }
  63990. if ($tokens[$prevIndex]->equals('@')) {
  63991. continue;
  63992. }
  63993. $tokens->insertAt($startIndex, new Token('@'));
  63994. continue;
  63995. }
  63996. if (!$tokens[$prevIndex]->equals('@')) {
  63997. continue;
  63998. }
  63999. if (true === $this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && !\in_array($tokens[$functionIndex]->getContent(), $excludedFunctions, true)) {
  64000. $tokens->clearAt($index);
  64001. }
  64002. }
  64003. }
  64004. private function isDeprecationErrorCall(Tokens $tokens, int $index): bool
  64005. {
  64006. if ('trigger_error' !== strtolower($tokens[$index]->getContent())) {
  64007. return false;
  64008. }
  64009. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextTokenOfKind($index, [[T_STRING], '(']));
  64010. $prevIndex = $tokens->getPrevMeaningfulToken($endBraceIndex);
  64011. if ($tokens[$prevIndex]->equals(',')) {
  64012. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  64013. }
  64014. return $tokens[$prevIndex]->equals([T_STRING, 'E_USER_DEPRECATED']);
  64015. }
  64016. }
  64017. <?php
  64018. declare(strict_types=1);
  64019. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64020. use PhpCsFixer\AbstractFixer;
  64021. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  64022. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  64023. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  64024. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  64025. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  64026. use PhpCsFixer\FixerDefinition\CodeSample;
  64027. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64028. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64029. use PhpCsFixer\Tokenizer\Token;
  64030. use PhpCsFixer\Tokenizer\Tokens;
  64031. /**
  64032. @phpstan-type
  64033. @phpstan-type
  64034. @implements
  64035. */
  64036. final class DeclareEqualNormalizeFixer extends AbstractFixer implements ConfigurableFixerInterface
  64037. {
  64038. /**
  64039. @use */
  64040. use ConfigurableFixerTrait;
  64041. public function getDefinition(): FixerDefinitionInterface
  64042. {
  64043. return new FixerDefinition(
  64044. 'Equal sign in declare statement should be surrounded by spaces or not following configuration.',
  64045. [
  64046. new CodeSample("<?php\ndeclare(ticks = 1);\n"),
  64047. new CodeSample("<?php\ndeclare(ticks=1);\n", ['space' => 'single']),
  64048. ]
  64049. );
  64050. }
  64051. public function getPriority(): int
  64052. {
  64053. return 0;
  64054. }
  64055. public function isCandidate(Tokens $tokens): bool
  64056. {
  64057. return $tokens->isTokenKindFound(T_DECLARE);
  64058. }
  64059. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  64060. {
  64061. for ($index = 0, $count = $tokens->count(); $index < $count - 6; ++$index) {
  64062. if (!$tokens[$index]->isGivenKind(T_DECLARE)) {
  64063. continue;
  64064. }
  64065. $openParenthesisIndex = $tokens->getNextMeaningfulToken($index);
  64066. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  64067. for ($i = $closeParenthesisIndex; $i > $openParenthesisIndex; --$i) {
  64068. if ($tokens[$i]->equals('=')) {
  64069. if ('none' === $this->configuration['space']) {
  64070. $this->removeWhitespaceAroundToken($tokens, $i);
  64071. } else {
  64072. $this->ensureWhitespaceAroundToken($tokens, $i);
  64073. }
  64074. }
  64075. }
  64076. }
  64077. }
  64078. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  64079. {
  64080. return new FixerConfigurationResolver([
  64081. (new FixerOptionBuilder('space', 'Spacing to apply around the equal sign.'))
  64082. ->setAllowedValues(['single', 'none'])
  64083. ->setDefault('none')
  64084. ->getOption(),
  64085. ]);
  64086. }
  64087. private function ensureWhitespaceAroundToken(Tokens $tokens, int $index): void
  64088. {
  64089. if ($tokens[$index + 1]->isWhitespace()) {
  64090. if (' ' !== $tokens[$index + 1]->getContent()) {
  64091. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  64092. }
  64093. } else {
  64094. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  64095. }
  64096. if ($tokens[$index - 1]->isWhitespace()) {
  64097. if (' ' !== $tokens[$index - 1]->getContent() && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  64098. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  64099. }
  64100. } else {
  64101. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  64102. }
  64103. }
  64104. private function removeWhitespaceAroundToken(Tokens $tokens, int $index): void
  64105. {
  64106. if (!$tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  64107. $tokens->removeLeadingWhitespace($index);
  64108. }
  64109. $tokens->removeTrailingWhitespace($index);
  64110. }
  64111. }
  64112. <?php
  64113. declare(strict_types=1);
  64114. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64115. use PhpCsFixer\AbstractFixer;
  64116. use PhpCsFixer\FixerDefinition\CodeSample;
  64117. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64118. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64119. use PhpCsFixer\Tokenizer\Tokens;
  64120. final class DeclareParenthesesFixer extends AbstractFixer
  64121. {
  64122. public function getDefinition(): FixerDefinitionInterface
  64123. {
  64124. return new FixerDefinition(
  64125. 'There must not be spaces around `declare` statement parentheses.',
  64126. [new CodeSample("<?php declare ( strict_types=1 );\n")]
  64127. );
  64128. }
  64129. public function isCandidate(Tokens $tokens): bool
  64130. {
  64131. return $tokens->isTokenKindFound(T_DECLARE);
  64132. }
  64133. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  64134. {
  64135. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  64136. $token = $tokens[$index];
  64137. if (!$token->isGivenKind(T_DECLARE)) {
  64138. continue;
  64139. }
  64140. $tokens->removeTrailingWhitespace($index);
  64141. $startParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(']);
  64142. $tokens->removeTrailingWhitespace($startParenthesisIndex);
  64143. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
  64144. $tokens->removeLeadingWhitespace($endParenthesisIndex);
  64145. }
  64146. }
  64147. }
  64148. <?php
  64149. declare(strict_types=1);
  64150. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64151. use PhpCsFixer\AbstractFixer;
  64152. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  64153. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  64154. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  64155. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  64156. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  64157. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  64158. use PhpCsFixer\FixerDefinition\CodeSample;
  64159. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64160. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64161. use PhpCsFixer\Preg;
  64162. use PhpCsFixer\Tokenizer\CT;
  64163. use PhpCsFixer\Tokenizer\FCT;
  64164. use PhpCsFixer\Tokenizer\Token;
  64165. use PhpCsFixer\Tokenizer\Tokens;
  64166. /**
  64167. @phpstan-type
  64168. @phpstan-type
  64169. @implements
  64170. */
  64171. final class SingleSpaceAroundConstructFixer extends AbstractFixer implements ConfigurableFixerInterface
  64172. {
  64173. /**
  64174. @use */
  64175. use ConfigurableFixerTrait;
  64176. private const TOKEN_MAP_CONTAIN_A_SINGLE_SPACE = [
  64177. 'yield_from' => T_YIELD_FROM,
  64178. ];
  64179. private const TOKEN_MAP_PRECEDED_BY_A_SINGLE_SPACE = [
  64180. 'as' => T_AS,
  64181. 'else' => T_ELSE,
  64182. 'elseif' => T_ELSEIF,
  64183. 'use_lambda' => CT::T_USE_LAMBDA,
  64184. ];
  64185. private const TOKEN_MAP_FOLLOWED_BY_A_SINGLE_SPACE = [
  64186. 'abstract' => T_ABSTRACT,
  64187. 'as' => T_AS,
  64188. 'attribute' => CT::T_ATTRIBUTE_CLOSE,
  64189. 'break' => T_BREAK,
  64190. 'case' => T_CASE,
  64191. 'catch' => T_CATCH,
  64192. 'class' => T_CLASS,
  64193. 'clone' => T_CLONE,
  64194. 'comment' => T_COMMENT,
  64195. 'const' => T_CONST,
  64196. 'const_import' => CT::T_CONST_IMPORT,
  64197. 'continue' => T_CONTINUE,
  64198. 'do' => T_DO,
  64199. 'echo' => T_ECHO,
  64200. 'else' => T_ELSE,
  64201. 'elseif' => T_ELSEIF,
  64202. 'enum' => FCT::T_ENUM,
  64203. 'extends' => T_EXTENDS,
  64204. 'final' => T_FINAL,
  64205. 'finally' => T_FINALLY,
  64206. 'for' => T_FOR,
  64207. 'foreach' => T_FOREACH,
  64208. 'function' => T_FUNCTION,
  64209. 'function_import' => CT::T_FUNCTION_IMPORT,
  64210. 'global' => T_GLOBAL,
  64211. 'goto' => T_GOTO,
  64212. 'if' => T_IF,
  64213. 'implements' => T_IMPLEMENTS,
  64214. 'include' => T_INCLUDE,
  64215. 'include_once' => T_INCLUDE_ONCE,
  64216. 'instanceof' => T_INSTANCEOF,
  64217. 'insteadof' => T_INSTEADOF,
  64218. 'interface' => T_INTERFACE,
  64219. 'match' => FCT::T_MATCH,
  64220. 'named_argument' => CT::T_NAMED_ARGUMENT_COLON,
  64221. 'namespace' => T_NAMESPACE,
  64222. 'new' => T_NEW,
  64223. 'open_tag_with_echo' => T_OPEN_TAG_WITH_ECHO,
  64224. 'php_doc' => T_DOC_COMMENT,
  64225. 'php_open' => T_OPEN_TAG,
  64226. 'print' => T_PRINT,
  64227. 'private' => T_PRIVATE,
  64228. 'private_set' => FCT::T_PRIVATE_SET,
  64229. 'protected' => T_PROTECTED,
  64230. 'protected_set' => FCT::T_PROTECTED_SET,
  64231. 'public' => T_PUBLIC,
  64232. 'public_set' => FCT::T_PUBLIC_SET,
  64233. 'readonly' => FCT::T_READONLY,
  64234. 'require' => T_REQUIRE,
  64235. 'require_once' => T_REQUIRE_ONCE,
  64236. 'return' => T_RETURN,
  64237. 'static' => T_STATIC,
  64238. 'switch' => T_SWITCH,
  64239. 'throw' => T_THROW,
  64240. 'trait' => T_TRAIT,
  64241. 'try' => T_TRY,
  64242. 'type_colon' => CT::T_TYPE_COLON,
  64243. 'use' => T_USE,
  64244. 'use_lambda' => CT::T_USE_LAMBDA,
  64245. 'use_trait' => CT::T_USE_TRAIT,
  64246. 'var' => T_VAR,
  64247. 'while' => T_WHILE,
  64248. 'yield' => T_YIELD,
  64249. 'yield_from' => T_YIELD_FROM,
  64250. ];
  64251. private array $fixTokenMapFollowedByASingleSpace = [];
  64252. private array $fixTokenMapContainASingleSpace = [];
  64253. private array $fixTokenMapPrecededByASingleSpace = [];
  64254. public function getDefinition(): FixerDefinitionInterface
  64255. {
  64256. return new FixerDefinition(
  64257. 'Ensures a single space after language constructs.',
  64258. [
  64259. new CodeSample(
  64260. '<?php
  64261. throw new \Exception();
  64262. '
  64263. ),
  64264. new CodeSample(
  64265. '<?php
  64266. function foo() { yield from baz(); }
  64267. ',
  64268. [
  64269. 'constructs_contain_a_single_space' => [
  64270. 'yield_from',
  64271. ],
  64272. 'constructs_followed_by_a_single_space' => [
  64273. 'yield_from',
  64274. ],
  64275. ]
  64276. ),
  64277. new CodeSample(
  64278. '<?php
  64279. $foo = function& ()use($bar) {
  64280. };
  64281. ',
  64282. [
  64283. 'constructs_preceded_by_a_single_space' => [
  64284. 'use_lambda',
  64285. ],
  64286. 'constructs_followed_by_a_single_space' => [
  64287. 'use_lambda',
  64288. ],
  64289. ]
  64290. ),
  64291. new CodeSample(
  64292. '<?php
  64293. echo "Hello!";
  64294. ',
  64295. [
  64296. 'constructs_followed_by_a_single_space' => [
  64297. 'echo',
  64298. ],
  64299. ]
  64300. ),
  64301. new CodeSample(
  64302. '<?php
  64303. yield from baz();
  64304. ',
  64305. [
  64306. 'constructs_followed_by_a_single_space' => [
  64307. 'yield_from',
  64308. ],
  64309. ]
  64310. ),
  64311. ]
  64312. );
  64313. }
  64314. public function getPriority(): int
  64315. {
  64316. return 36;
  64317. }
  64318. public function isCandidate(Tokens $tokens): bool
  64319. {
  64320. $tokenKinds = [
  64321. ...array_values($this->fixTokenMapContainASingleSpace),
  64322. ...array_values($this->fixTokenMapPrecededByASingleSpace),
  64323. ...array_values($this->fixTokenMapFollowedByASingleSpace),
  64324. ];
  64325. return $tokens->isAnyTokenKindsFound($tokenKinds);
  64326. }
  64327. protected function configurePostNormalisation(): void
  64328. {
  64329. $this->fixTokenMapContainASingleSpace = [];
  64330. foreach ($this->configuration['constructs_contain_a_single_space'] as $key) {
  64331. $this->fixTokenMapContainASingleSpace[$key] = self::TOKEN_MAP_CONTAIN_A_SINGLE_SPACE[$key];
  64332. }
  64333. $this->fixTokenMapPrecededByASingleSpace = [];
  64334. foreach ($this->configuration['constructs_preceded_by_a_single_space'] as $key) {
  64335. $this->fixTokenMapPrecededByASingleSpace[$key] = self::TOKEN_MAP_PRECEDED_BY_A_SINGLE_SPACE[$key];
  64336. }
  64337. $this->fixTokenMapFollowedByASingleSpace = [];
  64338. foreach ($this->configuration['constructs_followed_by_a_single_space'] as $key) {
  64339. $this->fixTokenMapFollowedByASingleSpace[$key] = self::TOKEN_MAP_FOLLOWED_BY_A_SINGLE_SPACE[$key];
  64340. }
  64341. if (isset($this->fixTokenMapFollowedByASingleSpace['public'])) {
  64342. $this->fixTokenMapFollowedByASingleSpace['constructor_public'] = CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC;
  64343. }
  64344. if (isset($this->fixTokenMapFollowedByASingleSpace['protected'])) {
  64345. $this->fixTokenMapFollowedByASingleSpace['constructor_protected'] = CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED;
  64346. }
  64347. if (isset($this->fixTokenMapFollowedByASingleSpace['private'])) {
  64348. $this->fixTokenMapFollowedByASingleSpace['constructor_private'] = CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE;
  64349. }
  64350. }
  64351. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  64352. {
  64353. $tokenKindsContainASingleSpace = array_values($this->fixTokenMapContainASingleSpace);
  64354. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  64355. if ($tokens[$index]->isGivenKind($tokenKindsContainASingleSpace)) {
  64356. $token = $tokens[$index];
  64357. if (
  64358. $token->isGivenKind(T_YIELD_FROM)
  64359. && 'yield from' !== strtolower($token->getContent())
  64360. ) {
  64361. $tokens[$index] = new Token([T_YIELD_FROM, Preg::replace(
  64362. '/\s+/',
  64363. ' ',
  64364. $token->getContent()
  64365. )]);
  64366. }
  64367. }
  64368. }
  64369. $tokenKindsPrecededByASingleSpace = array_values($this->fixTokenMapPrecededByASingleSpace);
  64370. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  64371. if ($tokens[$index]->isGivenKind($tokenKindsPrecededByASingleSpace)) {
  64372. if (!$this->isFullLineCommentBefore($tokens, $index)) {
  64373. $tokens->ensureWhitespaceAtIndex($index - 1, 1, ' ');
  64374. }
  64375. }
  64376. }
  64377. $tokenKindsFollowedByASingleSpace = array_values($this->fixTokenMapFollowedByASingleSpace);
  64378. for ($index = $tokens->count() - 2; $index >= 0; --$index) {
  64379. $token = $tokens[$index];
  64380. if (!$token->isGivenKind($tokenKindsFollowedByASingleSpace)) {
  64381. continue;
  64382. }
  64383. $whitespaceTokenIndex = $index + 1;
  64384. if ($tokens[$whitespaceTokenIndex]->equalsAny([',', ':', ';', ')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE], [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]])) {
  64385. continue;
  64386. }
  64387. if (
  64388. $token->isGivenKind(T_STATIC)
  64389. && !$tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind([T_FN, T_FUNCTION, T_NS_SEPARATOR, T_STRING, T_VARIABLE, CT::T_ARRAY_TYPEHINT, CT::T_NULLABLE_TYPE])
  64390. ) {
  64391. continue;
  64392. }
  64393. if ($token->isGivenKind(T_OPEN_TAG)) {
  64394. if ($tokens[$whitespaceTokenIndex]->equals([T_WHITESPACE]) && !str_contains($tokens[$whitespaceTokenIndex]->getContent(), "\n") && !str_contains($token->getContent(), "\n")) {
  64395. $tokens->clearAt($whitespaceTokenIndex);
  64396. }
  64397. continue;
  64398. }
  64399. if ($token->isGivenKind(T_CLASS) && $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(')) {
  64400. continue;
  64401. }
  64402. if ($token->isGivenKind([T_EXTENDS, T_IMPLEMENTS]) && $this->isMultilineExtendsOrImplementsWithMoreThanOneAncestor($tokens, $index)) {
  64403. continue;
  64404. }
  64405. if ($token->isGivenKind(T_RETURN) && $this->isMultiLineReturn($tokens, $index)) {
  64406. continue;
  64407. }
  64408. if ($token->isGivenKind(T_CONST) && $this->isMultilineCommaSeparatedConstant($tokens, $index)) {
  64409. continue;
  64410. }
  64411. if ($token->isComment() || $token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  64412. if ($tokens[$whitespaceTokenIndex]->equals([T_WHITESPACE]) && str_contains($tokens[$whitespaceTokenIndex]->getContent(), "\n")) {
  64413. continue;
  64414. }
  64415. }
  64416. if ($tokens[$whitespaceTokenIndex]->isWhitespace() && str_contains($tokens[$whitespaceTokenIndex]->getContent(), "\n")) {
  64417. $nextNextToken = $tokens[$whitespaceTokenIndex + 1];
  64418. if (
  64419. $nextNextToken->isGivenKind(FCT::T_ATTRIBUTE)
  64420. || $nextNextToken->isComment() && str_starts_with($nextNextToken->getContent(), '#[')
  64421. ) {
  64422. continue;
  64423. }
  64424. if ($nextNextToken->isGivenKind(T_DOC_COMMENT)) {
  64425. continue;
  64426. }
  64427. }
  64428. $tokens->ensureWhitespaceAtIndex($whitespaceTokenIndex, 0, ' ');
  64429. }
  64430. }
  64431. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  64432. {
  64433. $tokenMapContainASingleSpaceKeys = array_keys(self::TOKEN_MAP_CONTAIN_A_SINGLE_SPACE);
  64434. $tokenMapPrecededByASingleSpaceKeys = array_keys(self::TOKEN_MAP_PRECEDED_BY_A_SINGLE_SPACE);
  64435. $tokenMapFollowedByASingleSpaceKeys = array_keys(self::TOKEN_MAP_FOLLOWED_BY_A_SINGLE_SPACE);
  64436. return new FixerConfigurationResolver([
  64437. (new FixerOptionBuilder('constructs_contain_a_single_space', 'List of constructs which must contain a single space.'))
  64438. ->setAllowedTypes(['string[]'])
  64439. ->setAllowedValues([new AllowedValueSubset($tokenMapContainASingleSpaceKeys)])
  64440. ->setDefault($tokenMapContainASingleSpaceKeys)
  64441. ->getOption(),
  64442. (new FixerOptionBuilder('constructs_preceded_by_a_single_space', 'List of constructs which must be preceded by a single space.'))
  64443. ->setAllowedTypes(['string[]'])
  64444. ->setAllowedValues([new AllowedValueSubset($tokenMapPrecededByASingleSpaceKeys)])
  64445. ->setDefault(['as', 'use_lambda'])
  64446. ->getOption(),
  64447. (new FixerOptionBuilder('constructs_followed_by_a_single_space', 'List of constructs which must be followed by a single space.'))
  64448. ->setAllowedTypes(['string[]'])
  64449. ->setAllowedValues([new AllowedValueSubset($tokenMapFollowedByASingleSpaceKeys)])
  64450. ->setDefault($tokenMapFollowedByASingleSpaceKeys)
  64451. ->getOption(),
  64452. ]);
  64453. }
  64454. private function isMultiLineReturn(Tokens $tokens, int $index): bool
  64455. {
  64456. ++$index;
  64457. $tokenFollowingReturn = $tokens[$index];
  64458. if (
  64459. !$tokenFollowingReturn->isGivenKind(T_WHITESPACE)
  64460. || !str_contains($tokenFollowingReturn->getContent(), "\n")
  64461. ) {
  64462. return false;
  64463. }
  64464. $nestedCount = 0;
  64465. for ($indexEnd = \count($tokens) - 1, ++$index; $index < $indexEnd; ++$index) {
  64466. if (str_contains($tokens[$index]->getContent(), "\n")) {
  64467. return true;
  64468. }
  64469. if ($tokens[$index]->equals('{')) {
  64470. ++$nestedCount;
  64471. } elseif ($tokens[$index]->equals('}')) {
  64472. --$nestedCount;
  64473. } elseif (0 === $nestedCount && $tokens[$index]->equalsAny([';', [T_CLOSE_TAG]])) {
  64474. break;
  64475. }
  64476. }
  64477. return false;
  64478. }
  64479. private function isMultilineExtendsOrImplementsWithMoreThanOneAncestor(Tokens $tokens, int $index): bool
  64480. {
  64481. $hasMoreThanOneAncestor = false;
  64482. while (true) {
  64483. ++$index;
  64484. $token = $tokens[$index];
  64485. if ($token->equals(',')) {
  64486. $hasMoreThanOneAncestor = true;
  64487. continue;
  64488. }
  64489. if ($token->equals('{')) {
  64490. return false;
  64491. }
  64492. if ($hasMoreThanOneAncestor && str_contains($token->getContent(), "\n")) {
  64493. return true;
  64494. }
  64495. }
  64496. return LogicException('Not reachable code was reached.');
  64497. }
  64498. private function isMultilineCommaSeparatedConstant(Tokens $tokens, int $constantIndex): bool
  64499. {
  64500. $isMultilineConstant = false;
  64501. $hasMoreThanOneConstant = false;
  64502. $index = $constantIndex;
  64503. while (!$tokens[$index]->equalsAny([';', [T_CLOSE_TAG]])) {
  64504. ++$index;
  64505. $isMultilineConstant = $isMultilineConstant || str_contains($tokens[$index]->getContent(), "\n");
  64506. if ($tokens[$index]->equals(',')) {
  64507. $hasMoreThanOneConstant = true;
  64508. }
  64509. $blockType = Tokens::detectBlockType($tokens[$index]);
  64510. if (null !== $blockType && true === $blockType['isStart']) {
  64511. $index = $tokens->findBlockEnd($blockType['type'], $index);
  64512. }
  64513. }
  64514. return $hasMoreThanOneConstant && $isMultilineConstant;
  64515. }
  64516. private function isFullLineCommentBefore(Tokens $tokens, int $index): bool
  64517. {
  64518. $beforeIndex = $tokens->getPrevNonWhitespace($index);
  64519. if (!$tokens[$beforeIndex]->isGivenKind([T_COMMENT])) {
  64520. return false;
  64521. }
  64522. $content = $tokens[$beforeIndex]->getContent();
  64523. return str_starts_with($content, '#') || str_starts_with($content, '//');
  64524. }
  64525. }
  64526. <?php
  64527. declare(strict_types=1);
  64528. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64529. use PhpCsFixer\AbstractFixer;
  64530. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  64531. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  64532. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  64533. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  64534. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  64535. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  64536. use PhpCsFixer\FixerDefinition\CodeSample;
  64537. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64538. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64539. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  64540. use PhpCsFixer\Tokenizer\CT;
  64541. use PhpCsFixer\Tokenizer\Token;
  64542. use PhpCsFixer\Tokenizer\Tokens;
  64543. /**
  64544. @phpstan-type
  64545. @phpstan-type
  64546. @implements
  64547. */
  64548. final class FunctionToConstantFixer extends AbstractFixer implements ConfigurableFixerInterface
  64549. {
  64550. /**
  64551. @use */
  64552. use ConfigurableFixerTrait;
  64553. private static ?array $availableFunctions = null;
  64554. private array $functionsFixMap;
  64555. public function __construct()
  64556. {
  64557. if (null === self::$availableFunctions) {
  64558. self::$availableFunctions = [
  64559. 'get_called_class' => [
  64560. new Token([T_STATIC, 'static']),
  64561. new Token([T_DOUBLE_COLON, '::']),
  64562. new Token([CT::T_CLASS_CONSTANT, 'class']),
  64563. ],
  64564. 'get_class' => [
  64565. new Token([T_STRING, 'self']),
  64566. new Token([T_DOUBLE_COLON, '::']),
  64567. new Token([CT::T_CLASS_CONSTANT, 'class']),
  64568. ],
  64569. 'get_class_this' => [
  64570. new Token([T_STATIC, 'static']),
  64571. new Token([T_DOUBLE_COLON, '::']),
  64572. new Token([CT::T_CLASS_CONSTANT, 'class']),
  64573. ],
  64574. 'php_sapi_name' => [new Token([T_STRING, 'PHP_SAPI'])],
  64575. 'phpversion' => [new Token([T_STRING, 'PHP_VERSION'])],
  64576. 'pi' => [new Token([T_STRING, 'M_PI'])],
  64577. ];
  64578. }
  64579. parent::__construct();
  64580. }
  64581. public function getDefinition(): FixerDefinitionInterface
  64582. {
  64583. return new FixerDefinition(
  64584. 'Replace core functions calls returning constants with the constants.',
  64585. [
  64586. new CodeSample(
  64587. "<?php\necho phpversion();\necho pi();\necho php_sapi_name();\nclass Foo\n{\n public function Bar()\n {\n echo get_class();\n echo get_called_class();\n }\n}\n"
  64588. ),
  64589. new CodeSample(
  64590. "<?php\necho phpversion();\necho pi();\nclass Foo\n{\n public function Bar()\n {\n echo get_class();\n get_class(\$this);\n echo get_called_class();\n }\n}\n",
  64591. ['functions' => ['get_called_class', 'get_class_this', 'phpversion']]
  64592. ),
  64593. ],
  64594. null,
  64595. 'Risky when any of the configured functions to replace are overridden.'
  64596. );
  64597. }
  64598. public function getPriority(): int
  64599. {
  64600. return 2;
  64601. }
  64602. public function isCandidate(Tokens $tokens): bool
  64603. {
  64604. return $tokens->isTokenKindFound(T_STRING);
  64605. }
  64606. public function isRisky(): bool
  64607. {
  64608. return true;
  64609. }
  64610. protected function configurePostNormalisation(): void
  64611. {
  64612. $this->functionsFixMap = [];
  64613. foreach ($this->configuration['functions'] as $key) {
  64614. $this->functionsFixMap[$key] = self::$availableFunctions[$key];
  64615. }
  64616. }
  64617. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  64618. {
  64619. $functionAnalyzer = new FunctionsAnalyzer();
  64620. for ($index = $tokens->count() - 4; $index > 0; --$index) {
  64621. $candidate = $this->getReplaceCandidate($tokens, $functionAnalyzer, $index);
  64622. if (null === $candidate) {
  64623. continue;
  64624. }
  64625. $this->fixFunctionCallToConstant(
  64626. $tokens,
  64627. $index,
  64628. $candidate[0],
  64629. $candidate[1],
  64630. $candidate[2]
  64631. );
  64632. }
  64633. }
  64634. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  64635. {
  64636. $functionNames = array_keys(self::$availableFunctions);
  64637. return new FixerConfigurationResolver([
  64638. (new FixerOptionBuilder('functions', 'List of function names to fix.'))
  64639. ->setAllowedTypes(['string[]'])
  64640. ->setAllowedValues([new AllowedValueSubset($functionNames)])
  64641. ->setDefault([
  64642. 'get_called_class',
  64643. 'get_class',
  64644. 'get_class_this',
  64645. 'php_sapi_name',
  64646. 'phpversion',
  64647. 'pi',
  64648. ])
  64649. ->getOption(),
  64650. ]);
  64651. }
  64652. private function fixFunctionCallToConstant(Tokens $tokens, int $index, int $braceOpenIndex, int $braceCloseIndex, array $replacements): void
  64653. {
  64654. for ($i = $braceCloseIndex; $i >= $braceOpenIndex; --$i) {
  64655. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  64656. continue;
  64657. }
  64658. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  64659. }
  64660. if (
  64661. $replacements[0]->isGivenKind([T_CLASS_C, T_STATIC])
  64662. || ($replacements[0]->isGivenKind(T_STRING) && 'self' === $replacements[0]->getContent())
  64663. ) {
  64664. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  64665. $prevToken = $tokens[$prevIndex];
  64666. if ($prevToken->isGivenKind(T_NS_SEPARATOR)) {
  64667. $tokens->clearAt($prevIndex);
  64668. }
  64669. }
  64670. $tokens->clearAt($index);
  64671. $tokens->insertAt($index, $replacements);
  64672. }
  64673. private function getReplaceCandidate(
  64674. Tokens $tokens,
  64675. FunctionsAnalyzer $functionAnalyzer,
  64676. int $index
  64677. ): ?array {
  64678. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  64679. return null;
  64680. }
  64681. $lowerContent = strtolower($tokens[$index]->getContent());
  64682. if ('get_class' === $lowerContent) {
  64683. return $this->fixGetClassCall($tokens, $functionAnalyzer, $index);
  64684. }
  64685. if (!isset($this->functionsFixMap[$lowerContent])) {
  64686. return null;
  64687. }
  64688. if (!$functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  64689. return null;
  64690. }
  64691. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  64692. if (!$tokens[$braceOpenIndex]->equals('(')) {
  64693. return null;
  64694. }
  64695. $braceCloseIndex = $tokens->getNextMeaningfulToken($braceOpenIndex);
  64696. if (!$tokens[$braceCloseIndex]->equals(')')) {
  64697. return null;
  64698. }
  64699. return $this->getReplacementTokenClones($lowerContent, $braceOpenIndex, $braceCloseIndex);
  64700. }
  64701. private function fixGetClassCall(
  64702. Tokens $tokens,
  64703. FunctionsAnalyzer $functionAnalyzer,
  64704. int $index
  64705. ): ?array {
  64706. if (!isset($this->functionsFixMap['get_class']) && !isset($this->functionsFixMap['get_class_this'])) {
  64707. return null;
  64708. }
  64709. if (!$functionAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  64710. return null;
  64711. }
  64712. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  64713. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceOpenIndex);
  64714. if ($braceCloseIndex === $tokens->getNextMeaningfulToken($braceOpenIndex)) {
  64715. if (isset($this->functionsFixMap['get_class'])) {
  64716. return $this->getReplacementTokenClones('get_class', $braceOpenIndex, $braceCloseIndex);
  64717. }
  64718. } elseif (isset($this->functionsFixMap['get_class_this'])) {
  64719. $isThis = false;
  64720. for ($i = $braceOpenIndex + 1; $i < $braceCloseIndex; ++$i) {
  64721. if ($tokens[$i]->equalsAny([[T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT], ')'])) {
  64722. continue;
  64723. }
  64724. if ($tokens[$i]->isGivenKind(T_VARIABLE) && '$this' === strtolower($tokens[$i]->getContent())) {
  64725. $isThis = true;
  64726. continue;
  64727. }
  64728. if (false === $isThis && $tokens[$i]->equals('(')) {
  64729. continue;
  64730. }
  64731. $isThis = false;
  64732. break;
  64733. }
  64734. if ($isThis) {
  64735. return $this->getReplacementTokenClones('get_class_this', $braceOpenIndex, $braceCloseIndex);
  64736. }
  64737. }
  64738. return null;
  64739. }
  64740. private function getReplacementTokenClones(string $lowerContent, int $braceOpenIndex, int $braceCloseIndex): array
  64741. {
  64742. $clones = array_map(
  64743. static fn (Token $token): Token => clone $token,
  64744. $this->functionsFixMap[$lowerContent],
  64745. );
  64746. return [
  64747. $braceOpenIndex,
  64748. $braceCloseIndex,
  64749. $clones,
  64750. ];
  64751. }
  64752. }
  64753. <?php
  64754. declare(strict_types=1);
  64755. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64756. use PhpCsFixer\AbstractProxyFixer;
  64757. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  64758. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  64759. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  64760. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  64761. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  64762. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  64763. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  64764. use PhpCsFixer\FixerDefinition\CodeSample;
  64765. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64766. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64767. use PhpCsFixer\Tokenizer\CT;
  64768. /**
  64769. @phpstan-type
  64770. @phpstan-type
  64771. @implements
  64772. */
  64773. final class SingleSpaceAfterConstructFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface
  64774. {
  64775. /**
  64776. @use */
  64777. use ConfigurableFixerTrait;
  64778. private const TOKEN_MAP = [
  64779. 'abstract' => T_ABSTRACT,
  64780. 'as' => T_AS,
  64781. 'attribute' => CT::T_ATTRIBUTE_CLOSE,
  64782. 'break' => T_BREAK,
  64783. 'case' => T_CASE,
  64784. 'catch' => T_CATCH,
  64785. 'class' => T_CLASS,
  64786. 'clone' => T_CLONE,
  64787. 'comment' => T_COMMENT,
  64788. 'const' => T_CONST,
  64789. 'const_import' => CT::T_CONST_IMPORT,
  64790. 'continue' => T_CONTINUE,
  64791. 'do' => T_DO,
  64792. 'echo' => T_ECHO,
  64793. 'else' => T_ELSE,
  64794. 'elseif' => T_ELSEIF,
  64795. 'enum' => null,
  64796. 'extends' => T_EXTENDS,
  64797. 'final' => T_FINAL,
  64798. 'finally' => T_FINALLY,
  64799. 'for' => T_FOR,
  64800. 'foreach' => T_FOREACH,
  64801. 'function' => T_FUNCTION,
  64802. 'function_import' => CT::T_FUNCTION_IMPORT,
  64803. 'global' => T_GLOBAL,
  64804. 'goto' => T_GOTO,
  64805. 'if' => T_IF,
  64806. 'implements' => T_IMPLEMENTS,
  64807. 'include' => T_INCLUDE,
  64808. 'include_once' => T_INCLUDE_ONCE,
  64809. 'instanceof' => T_INSTANCEOF,
  64810. 'insteadof' => T_INSTEADOF,
  64811. 'interface' => T_INTERFACE,
  64812. 'match' => null,
  64813. 'named_argument' => CT::T_NAMED_ARGUMENT_COLON,
  64814. 'namespace' => T_NAMESPACE,
  64815. 'new' => T_NEW,
  64816. 'open_tag_with_echo' => T_OPEN_TAG_WITH_ECHO,
  64817. 'php_doc' => T_DOC_COMMENT,
  64818. 'php_open' => T_OPEN_TAG,
  64819. 'print' => T_PRINT,
  64820. 'private' => T_PRIVATE,
  64821. 'protected' => T_PROTECTED,
  64822. 'public' => T_PUBLIC,
  64823. 'readonly' => null,
  64824. 'require' => T_REQUIRE,
  64825. 'require_once' => T_REQUIRE_ONCE,
  64826. 'return' => T_RETURN,
  64827. 'static' => T_STATIC,
  64828. 'switch' => T_SWITCH,
  64829. 'throw' => T_THROW,
  64830. 'trait' => T_TRAIT,
  64831. 'try' => T_TRY,
  64832. 'type_colon' => CT::T_TYPE_COLON,
  64833. 'use' => T_USE,
  64834. 'use_lambda' => CT::T_USE_LAMBDA,
  64835. 'use_trait' => CT::T_USE_TRAIT,
  64836. 'var' => T_VAR,
  64837. 'while' => T_WHILE,
  64838. 'yield' => T_YIELD,
  64839. 'yield_from' => T_YIELD_FROM,
  64840. ];
  64841. private SingleSpaceAroundConstructFixer $singleSpaceAroundConstructFixer;
  64842. public function __construct()
  64843. {
  64844. $this->singleSpaceAroundConstructFixer = new SingleSpaceAroundConstructFixer();
  64845. parent::__construct();
  64846. }
  64847. public function getSuccessorsNames(): array
  64848. {
  64849. return array_keys($this->proxyFixers);
  64850. }
  64851. public function getDefinition(): FixerDefinitionInterface
  64852. {
  64853. return new FixerDefinition(
  64854. 'Ensures a single space after language constructs.',
  64855. [
  64856. new CodeSample(
  64857. '<?php
  64858. throw new \Exception();
  64859. '
  64860. ),
  64861. new CodeSample(
  64862. '<?php
  64863. echo "Hello!";
  64864. ',
  64865. [
  64866. 'constructs' => [
  64867. 'echo',
  64868. ],
  64869. ]
  64870. ),
  64871. new CodeSample(
  64872. '<?php
  64873. yield from baz();
  64874. ',
  64875. [
  64876. 'constructs' => [
  64877. 'yield_from',
  64878. ],
  64879. ]
  64880. ),
  64881. ]
  64882. );
  64883. }
  64884. public function getPriority(): int
  64885. {
  64886. return parent::getPriority();
  64887. }
  64888. protected function configurePostNormalisation(): void
  64889. {
  64890. $this->singleSpaceAroundConstructFixer->configure([
  64891. 'constructs_contain_a_single_space' => [
  64892. 'yield_from',
  64893. ],
  64894. 'constructs_preceded_by_a_single_space' => [],
  64895. 'constructs_followed_by_a_single_space' => $this->configuration['constructs'],
  64896. ]);
  64897. }
  64898. protected function createProxyFixers(): array
  64899. {
  64900. return [$this->singleSpaceAroundConstructFixer];
  64901. }
  64902. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  64903. {
  64904. $defaults = self::TOKEN_MAP;
  64905. $tokens = array_keys($defaults);
  64906. unset($defaults['type_colon']);
  64907. return new FixerConfigurationResolver([
  64908. (new FixerOptionBuilder('constructs', 'List of constructs which must be followed by a single space.'))
  64909. ->setAllowedTypes(['string[]'])
  64910. ->setAllowedValues([new AllowedValueSubset($tokens)])
  64911. ->setDefault(array_keys($defaults))
  64912. ->getOption(),
  64913. ]);
  64914. }
  64915. }
  64916. <?php
  64917. declare(strict_types=1);
  64918. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64919. use PhpCsFixer\AbstractFixer;
  64920. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  64921. use PhpCsFixer\FixerDefinition\CodeSample;
  64922. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64923. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64924. use PhpCsFixer\Tokenizer\Tokens;
  64925. final class ClassKeywordFixer extends AbstractFixer implements ExperimentalFixerInterface
  64926. {
  64927. public function getDefinition(): FixerDefinitionInterface
  64928. {
  64929. return new FixerDefinition(
  64930. 'Converts FQCN strings to `*::class` keywords.',
  64931. [
  64932. new CodeSample(
  64933. '<?php
  64934. $foo = \'PhpCsFixer\Tokenizer\Tokens\';
  64935. $bar = "\PhpCsFixer\Tokenizer\Tokens";
  64936. '
  64937. ),
  64938. ],
  64939. 'This rule does not have an understanding of whether a class exists in the scope of the codebase or not, relying on run-time and autoloaded classes to determine it, which makes the rule useless when running on a single file out of codebase context.',
  64940. 'Do not use it, unless you know what you are doing.'
  64941. );
  64942. }
  64943. public function getPriority(): int
  64944. {
  64945. return 8;
  64946. }
  64947. public function isCandidate(Tokens $tokens): bool
  64948. {
  64949. return true;
  64950. }
  64951. public function isRisky(): bool
  64952. {
  64953. return true;
  64954. }
  64955. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  64956. {
  64957. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  64958. $token = $tokens[$index];
  64959. if ($token->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  64960. $name = substr($token->getContent(), 1, -1);
  64961. $name = ltrim($name, '\\');
  64962. $name = str_replace('\\\\', '\\', $name);
  64963. if ($this->exists($name)) {
  64964. $substitution = Tokens::fromCode("<?php echo \\{$name}::class;");
  64965. $substitution->clearRange(0, 2);
  64966. $substitution->clearAt($substitution->getSize() - 1);
  64967. $substitution->clearEmptyTokens();
  64968. $tokens->clearAt($index);
  64969. $tokens->insertAt($index, $substitution);
  64970. }
  64971. }
  64972. }
  64973. }
  64974. private function exists(string $name): bool
  64975. {
  64976. if (class_exists($name) || interface_exists($name) || trait_exists($name)) {
  64977. $rc = new \ReflectionClass($name);
  64978. return $rc->getName() === $name;
  64979. }
  64980. return false;
  64981. }
  64982. }
  64983. <?php
  64984. declare(strict_types=1);
  64985. namespace PhpCsFixer\Fixer\LanguageConstruct;
  64986. use PhpCsFixer\AbstractFixer;
  64987. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  64988. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  64989. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  64990. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  64991. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  64992. use PhpCsFixer\FixerDefinition\FixerDefinition;
  64993. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  64994. use PhpCsFixer\FixerDefinition\VersionSpecification;
  64995. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  64996. use PhpCsFixer\Preg;
  64997. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  64998. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  64999. use PhpCsFixer\Tokenizer\CT;
  65000. use PhpCsFixer\Tokenizer\FCT;
  65001. use PhpCsFixer\Tokenizer\Token;
  65002. use PhpCsFixer\Tokenizer\Tokens;
  65003. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  65004. /**
  65005. @phpstan-type
  65006. @phpstan-type
  65007. @implements
  65008. */
  65009. final class NullableTypeDeclarationFixer extends AbstractFixer implements ConfigurableFixerInterface
  65010. {
  65011. /**
  65012. @use */
  65013. use ConfigurableFixerTrait;
  65014. private const OPTION_SYNTAX_UNION = 'union';
  65015. private const OPTION_SYNTAX_QUESTION_MARK = 'question_mark';
  65016. private const PROPERTY_MODIFIERS = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  65017. private int $candidateTokenKind;
  65018. public function getDefinition(): FixerDefinitionInterface
  65019. {
  65020. return new FixerDefinition(
  65021. 'Nullable single type declaration should be standardised using configured syntax.',
  65022. [
  65023. new VersionSpecificCodeSample(
  65024. "<?php\nfunction bar(null|int \$value, null|\\Closure \$callable): int|null {}\n",
  65025. new VersionSpecification(8_00_00)
  65026. ),
  65027. new VersionSpecificCodeSample(
  65028. "<?php\nfunction baz(?int \$value, ?\\stdClass \$obj, ?array \$config): ?int {}\n",
  65029. new VersionSpecification(8_00_00),
  65030. ['syntax' => self::OPTION_SYNTAX_UNION]
  65031. ),
  65032. new VersionSpecificCodeSample(
  65033. '<?php
  65034. class ValueObject
  65035. {
  65036. public null|string $name;
  65037. public ?int $count;
  65038. public null|bool $internal;
  65039. public null|\Closure $callback;
  65040. }
  65041. ',
  65042. new VersionSpecification(8_00_00),
  65043. ['syntax' => self::OPTION_SYNTAX_QUESTION_MARK]
  65044. ),
  65045. ]
  65046. );
  65047. }
  65048. public function isCandidate(Tokens $tokens): bool
  65049. {
  65050. return \PHP_VERSION_ID >= 8_00_00 && $tokens->isTokenKindFound($this->candidateTokenKind);
  65051. }
  65052. public function getPriority(): int
  65053. {
  65054. return 2;
  65055. }
  65056. protected function configurePostNormalisation(): void
  65057. {
  65058. $this->candidateTokenKind = self::OPTION_SYNTAX_QUESTION_MARK === $this->configuration['syntax']
  65059. ? CT::T_TYPE_ALTERNATION
  65060. : CT::T_NULLABLE_TYPE;
  65061. }
  65062. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  65063. {
  65064. return new FixerConfigurationResolver([
  65065. (new FixerOptionBuilder('syntax', 'Whether to use question mark (`?`) or explicit `null` union for nullable type.'))
  65066. ->setAllowedValues([self::OPTION_SYNTAX_UNION, self::OPTION_SYNTAX_QUESTION_MARK])
  65067. ->setDefault(self::OPTION_SYNTAX_QUESTION_MARK)
  65068. ->getOption(),
  65069. ]);
  65070. }
  65071. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65072. {
  65073. $functionsAnalyzer = new FunctionsAnalyzer();
  65074. foreach (array_reverse($this->getElements($tokens), true) as $index => $type) {
  65075. if ('property' === $type) {
  65076. $this->normalizePropertyType($tokens, $index);
  65077. continue;
  65078. }
  65079. $this->normalizeMethodReturnType($functionsAnalyzer, $tokens, $index);
  65080. $this->normalizeMethodArgumentType($functionsAnalyzer, $tokens, $index);
  65081. }
  65082. }
  65083. /**
  65084. @phpstan-return
  65085. */
  65086. private function getElements(Tokens $tokens): array
  65087. {
  65088. $tokensAnalyzer = new TokensAnalyzer($tokens);
  65089. $elements = array_map(
  65090. static fn (array $element): string => 'method' === $element['type'] ? 'function' : $element['type'],
  65091. array_filter(
  65092. $tokensAnalyzer->getClassyElements(),
  65093. static fn (array $element): bool => \in_array($element['type'], ['method', 'property'], true)
  65094. )
  65095. );
  65096. foreach ($tokens as $index => $token) {
  65097. if (
  65098. $token->isGivenKind(T_FN)
  65099. || ($token->isGivenKind(T_FUNCTION) && !isset($elements[$index]))
  65100. ) {
  65101. $elements[$index] = 'function';
  65102. }
  65103. }
  65104. return $elements;
  65105. }
  65106. private function collectTypeAnalysis(Tokens $tokens, int $startIndex, int $endIndex): ?TypeAnalysis
  65107. {
  65108. $type = '';
  65109. $typeStartIndex = $tokens->getNextMeaningfulToken($startIndex);
  65110. $typeEndIndex = $typeStartIndex;
  65111. for ($i = $typeStartIndex; $i < $endIndex; ++$i) {
  65112. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  65113. continue;
  65114. }
  65115. $type .= $tokens[$i]->getContent();
  65116. $typeEndIndex = $i;
  65117. }
  65118. return '' !== $type ? new TypeAnalysis($type, $typeStartIndex, $typeEndIndex) : null;
  65119. }
  65120. private function isTypeNormalizable(TypeAnalysis $typeAnalysis): bool
  65121. {
  65122. $type = $typeAnalysis->getName();
  65123. if ('null' === strtolower($type) || !$typeAnalysis->isNullable()) {
  65124. return false;
  65125. }
  65126. if (str_contains($type, '&')) {
  65127. return false;
  65128. }
  65129. if (!str_contains($type, '|')) {
  65130. return true;
  65131. }
  65132. return 1 === substr_count($type, '|') && Preg::match('/(?:\|null$|^null\|)/i', $type);
  65133. }
  65134. private function normalizePropertyType(Tokens $tokens, int $index): void
  65135. {
  65136. $propertyEndIndex = $index;
  65137. do {
  65138. $index = $tokens->getPrevMeaningfulToken($index);
  65139. } while (!$tokens[$index]->isGivenKind(self::PROPERTY_MODIFIERS));
  65140. $propertyType = $this->collectTypeAnalysis($tokens, $index, $propertyEndIndex);
  65141. if (null === $propertyType || !$this->isTypeNormalizable($propertyType)) {
  65142. return;
  65143. }
  65144. $this->normalizeNullableType($tokens, $propertyType);
  65145. }
  65146. private function normalizeMethodArgumentType(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index): void
  65147. {
  65148. foreach (array_reverse($functionsAnalyzer->getFunctionArguments($tokens, $index), true) as $argumentInfo) {
  65149. $argumentType = $argumentInfo->getTypeAnalysis();
  65150. if (null === $argumentType || !$this->isTypeNormalizable($argumentType)) {
  65151. continue;
  65152. }
  65153. $this->normalizeNullableType($tokens, $argumentType);
  65154. }
  65155. }
  65156. private function normalizeMethodReturnType(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index): void
  65157. {
  65158. $returnType = $functionsAnalyzer->getFunctionReturnType($tokens, $index);
  65159. if (null === $returnType || !$this->isTypeNormalizable($returnType)) {
  65160. return;
  65161. }
  65162. $this->normalizeNullableType($tokens, $returnType);
  65163. }
  65164. private function normalizeNullableType(Tokens $tokens, TypeAnalysis $typeAnalysis): void
  65165. {
  65166. $type = $typeAnalysis->getName();
  65167. if (!str_contains($type, '|') && !str_contains($type, '&')) {
  65168. $type = ($typeAnalysis->isNullable() ? '?' : '').$type;
  65169. }
  65170. $isQuestionMarkSyntax = self::OPTION_SYNTAX_QUESTION_MARK === $this->configuration['syntax'];
  65171. if ($isQuestionMarkSyntax) {
  65172. $normalizedType = $this->convertToNullableType($type);
  65173. $normalizedTypeAsString = implode('', $normalizedType);
  65174. } else {
  65175. $normalizedType = $this->convertToExplicitUnionType($type);
  65176. $normalizedTypeAsString = implode('|', $normalizedType);
  65177. }
  65178. if ($normalizedTypeAsString === $type) {
  65179. return;
  65180. }
  65181. $tokens->overrideRange(
  65182. $typeAnalysis->getStartIndex(),
  65183. $typeAnalysis->getEndIndex(),
  65184. $this->createTypeDeclarationTokens($normalizedType, $isQuestionMarkSyntax)
  65185. );
  65186. $prevStartIndex = $typeAnalysis->getStartIndex() - 1;
  65187. if (!$tokens[$prevStartIndex]->isWhitespace() && !$tokens[$prevStartIndex]->equals('(')) {
  65188. $tokens->ensureWhitespaceAtIndex($prevStartIndex, 1, ' ');
  65189. }
  65190. }
  65191. private function convertToNullableType(string $type): array
  65192. {
  65193. if (str_starts_with($type, '?')) {
  65194. return [$type];
  65195. }
  65196. return ['?', Preg::replace('/(?:\|null$|^null\|)/i', '', $type)];
  65197. }
  65198. private function convertToExplicitUnionType(string $type): array
  65199. {
  65200. if (str_contains($type, '|')) {
  65201. return [$type];
  65202. }
  65203. return ['null', substr($type, 1)];
  65204. }
  65205. private function createTypeDeclarationTokens(array $types, bool $isQuestionMarkSyntax): array
  65206. {
  65207. static $specialTypes = [
  65208. '?' => CT::T_NULLABLE_TYPE,
  65209. 'array' => CT::T_ARRAY_TYPEHINT,
  65210. 'callable' => T_CALLABLE,
  65211. 'static' => T_STATIC,
  65212. ];
  65213. $count = \count($types);
  65214. $newTokens = [];
  65215. foreach ($types as $index => $type) {
  65216. if (isset($specialTypes[strtolower($type)])) {
  65217. $newTokens[] = new Token([$specialTypes[strtolower($type)], $type]);
  65218. } else {
  65219. foreach (explode('\\', $type) as $nsIndex => $value) {
  65220. if (0 === $nsIndex && '' === $value) {
  65221. continue;
  65222. }
  65223. if ($nsIndex > 0) {
  65224. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  65225. }
  65226. $newTokens[] = new Token([T_STRING, $value]);
  65227. }
  65228. }
  65229. if ($index <= $count - 2 && !$isQuestionMarkSyntax) {
  65230. $newTokens[] = new Token([CT::T_TYPE_ALTERNATION, '|']);
  65231. }
  65232. }
  65233. return $newTokens;
  65234. }
  65235. }
  65236. <?php
  65237. declare(strict_types=1);
  65238. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65239. use PhpCsFixer\AbstractFixer;
  65240. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65241. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65242. use PhpCsFixer\FixerDefinition\VersionSpecification;
  65243. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  65244. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  65245. use PhpCsFixer\Tokenizer\CT;
  65246. use PhpCsFixer\Tokenizer\Token;
  65247. use PhpCsFixer\Tokenizer\Tokens;
  65248. final class GetClassToClassKeywordFixer extends AbstractFixer
  65249. {
  65250. public function getDefinition(): FixerDefinitionInterface
  65251. {
  65252. return new FixerDefinition(
  65253. 'Replace `get_class` calls on object variables with class keyword syntax.',
  65254. [
  65255. new VersionSpecificCodeSample(
  65256. "<?php\nget_class(\$a);\n",
  65257. new VersionSpecification(8_00_00)
  65258. ),
  65259. new VersionSpecificCodeSample(
  65260. "<?php\n\n\$date = new \\DateTimeImmutable();\n\$class = get_class(\$date);\n",
  65261. new VersionSpecification(8_00_00)
  65262. ),
  65263. ],
  65264. null,
  65265. 'Risky if the `get_class` function is overridden.'
  65266. );
  65267. }
  65268. public function getPriority(): int
  65269. {
  65270. return 1;
  65271. }
  65272. public function isCandidate(Tokens $tokens): bool
  65273. {
  65274. return \PHP_VERSION_ID >= 8_00_00 && $tokens->isAllTokenKindsFound([T_STRING, T_VARIABLE]);
  65275. }
  65276. public function isRisky(): bool
  65277. {
  65278. return true;
  65279. }
  65280. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65281. {
  65282. $functionsAnalyzer = new FunctionsAnalyzer();
  65283. $indicesToClear = [];
  65284. $tokenSlices = [];
  65285. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  65286. if (!$tokens[$index]->equals([T_STRING, 'get_class'], false)) {
  65287. continue;
  65288. }
  65289. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  65290. continue;
  65291. }
  65292. $braceOpenIndex = $tokens->getNextMeaningfulToken($index);
  65293. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceOpenIndex);
  65294. if ($braceCloseIndex === $tokens->getNextMeaningfulToken($braceOpenIndex)) {
  65295. continue;
  65296. }
  65297. $meaningfulTokensCount = 0;
  65298. $variableTokensIndices = [];
  65299. for ($i = $braceOpenIndex + 1; $i < $braceCloseIndex; ++$i) {
  65300. if (!$tokens[$i]->equalsAny([[T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT], '(', ')'])) {
  65301. ++$meaningfulTokensCount;
  65302. }
  65303. if (!$tokens[$i]->isGivenKind(T_VARIABLE)) {
  65304. continue;
  65305. }
  65306. if ('$this' === strtolower($tokens[$i]->getContent())) {
  65307. continue 2;
  65308. }
  65309. $variableTokensIndices[] = $i;
  65310. }
  65311. if ($meaningfulTokensCount > 1 || 1 !== \count($variableTokensIndices)) {
  65312. continue;
  65313. }
  65314. $indicesToClear[$index] = [$braceOpenIndex, current($variableTokensIndices), $braceCloseIndex];
  65315. }
  65316. foreach ($indicesToClear as $index => $items) {
  65317. $tokenSlices[$index] = $this->getReplacementTokenSlices($tokens, $items[1]);
  65318. $this->clearGetClassCall($tokens, $index, $items[0], $items[2]);
  65319. }
  65320. $tokens->insertSlices($tokenSlices);
  65321. }
  65322. private function getReplacementTokenSlices(Tokens $tokens, int $variableIndex): array
  65323. {
  65324. return [
  65325. new Token([T_VARIABLE, $tokens[$variableIndex]->getContent()]),
  65326. new Token([T_DOUBLE_COLON, '::']),
  65327. new Token([CT::T_CLASS_CONSTANT, 'class']),
  65328. ];
  65329. }
  65330. private function clearGetClassCall(Tokens $tokens, int $index, int $braceOpenIndex, int $braceCloseIndex): void
  65331. {
  65332. for ($i = $braceOpenIndex; $i <= $braceCloseIndex; ++$i) {
  65333. if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  65334. continue;
  65335. }
  65336. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  65337. }
  65338. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  65339. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  65340. $tokens->clearAt($prevIndex);
  65341. }
  65342. $tokens->clearAt($index);
  65343. }
  65344. }
  65345. <?php
  65346. declare(strict_types=1);
  65347. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65348. use PhpCsFixer\AbstractFixer;
  65349. use PhpCsFixer\FixerDefinition\CodeSample;
  65350. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65351. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65352. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  65353. use PhpCsFixer\Tokenizer\Token;
  65354. use PhpCsFixer\Tokenizer\Tokens;
  65355. final class IsNullFixer extends AbstractFixer
  65356. {
  65357. public function getDefinition(): FixerDefinitionInterface
  65358. {
  65359. return new FixerDefinition(
  65360. 'Replaces `is_null($var)` expression with `null === $var`.',
  65361. [
  65362. new CodeSample("<?php\n\$a = is_null(\$b);\n"),
  65363. ],
  65364. null,
  65365. 'Risky when the function `is_null` is overridden.'
  65366. );
  65367. }
  65368. public function getPriority(): int
  65369. {
  65370. return 1;
  65371. }
  65372. public function isCandidate(Tokens $tokens): bool
  65373. {
  65374. return $tokens->isTokenKindFound(T_STRING);
  65375. }
  65376. public function isRisky(): bool
  65377. {
  65378. return true;
  65379. }
  65380. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65381. {
  65382. static $sequenceNeeded = [[T_STRING, 'is_null'], '('];
  65383. $functionsAnalyzer = new FunctionsAnalyzer();
  65384. $currIndex = 0;
  65385. while (true) {
  65386. $matches = $tokens->findSequence($sequenceNeeded, $currIndex, $tokens->count() - 1, false);
  65387. if (null === $matches) {
  65388. break;
  65389. }
  65390. $matches = array_keys($matches);
  65391. [$isNullIndex, $currIndex] = $matches;
  65392. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $matches[0])) {
  65393. continue;
  65394. }
  65395. $next = $tokens->getNextMeaningfulToken($currIndex);
  65396. if ($tokens[$next]->equals(')')) {
  65397. continue;
  65398. }
  65399. $prevTokenIndex = $tokens->getPrevMeaningfulToken($matches[0]);
  65400. if ($tokens[$prevTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  65401. $tokens->removeTrailingWhitespace($prevTokenIndex);
  65402. $tokens->clearAt($prevTokenIndex);
  65403. $prevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex);
  65404. }
  65405. $isInvertedNullCheck = false;
  65406. if ($tokens[$prevTokenIndex]->equals('!')) {
  65407. $isInvertedNullCheck = true;
  65408. $tokens->removeTrailingWhitespace($prevTokenIndex);
  65409. $tokens->clearAt($prevTokenIndex);
  65410. }
  65411. $referenceEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $matches[1]);
  65412. $isContainingDangerousConstructs = false;
  65413. for ($paramTokenIndex = $matches[1]; $paramTokenIndex <= $referenceEnd; ++$paramTokenIndex) {
  65414. if (\in_array($tokens[$paramTokenIndex]->getContent(), ['?', '?:', '=', '??'], true)) {
  65415. $isContainingDangerousConstructs = true;
  65416. break;
  65417. }
  65418. }
  65419. $parentLeftToken = $tokens[$tokens->getPrevMeaningfulToken($isNullIndex)];
  65420. $parentRightToken = $tokens[$tokens->getNextMeaningfulToken($referenceEnd)];
  65421. $parentOperations = [T_IS_EQUAL, T_IS_NOT_EQUAL, T_IS_IDENTICAL, T_IS_NOT_IDENTICAL];
  65422. $wrapIntoParentheses = $parentLeftToken->isCast() || $parentLeftToken->isGivenKind($parentOperations) || $parentRightToken->isGivenKind($parentOperations);
  65423. $prevIndex = $tokens->getPrevMeaningfulToken($referenceEnd);
  65424. if ($tokens[$prevIndex]->equals(',')) {
  65425. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  65426. }
  65427. if (!$isContainingDangerousConstructs) {
  65428. $tokens->removeLeadingWhitespace($referenceEnd);
  65429. $tokens->clearAt($referenceEnd);
  65430. $tokens->removeLeadingWhitespace($matches[1]);
  65431. $tokens->removeTrailingWhitespace($matches[1]);
  65432. $tokens->clearAt($matches[1]);
  65433. }
  65434. $replacement = [
  65435. new Token([T_STRING, 'null']),
  65436. new Token([T_WHITESPACE, ' ']),
  65437. new Token($isInvertedNullCheck ? [T_IS_NOT_IDENTICAL, '!=='] : [T_IS_IDENTICAL, '===']),
  65438. new Token([T_WHITESPACE, ' ']),
  65439. ];
  65440. if ($wrapIntoParentheses) {
  65441. array_unshift($replacement, new Token('('));
  65442. $tokens->insertAt($referenceEnd + 1, new Token(')'));
  65443. }
  65444. $tokens->overrideRange($isNullIndex, $isNullIndex, $replacement);
  65445. $currIndex = $isNullIndex;
  65446. }
  65447. }
  65448. }
  65449. <?php
  65450. declare(strict_types=1);
  65451. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65452. use PhpCsFixer\AbstractFixer;
  65453. use PhpCsFixer\FixerDefinition\CodeSample;
  65454. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65455. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65456. use PhpCsFixer\Tokenizer\Token;
  65457. use PhpCsFixer\Tokenizer\Tokens;
  65458. final class CombineConsecutiveUnsetsFixer extends AbstractFixer
  65459. {
  65460. public function getDefinition(): FixerDefinitionInterface
  65461. {
  65462. return new FixerDefinition(
  65463. 'Calling `unset` on multiple items should be done in one call.',
  65464. [new CodeSample("<?php\nunset(\$a); unset(\$b);\n")]
  65465. );
  65466. }
  65467. public function getPriority(): int
  65468. {
  65469. return 24;
  65470. }
  65471. public function isCandidate(Tokens $tokens): bool
  65472. {
  65473. return $tokens->isTokenKindFound(T_UNSET);
  65474. }
  65475. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65476. {
  65477. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  65478. if (!$tokens[$index]->isGivenKind(T_UNSET)) {
  65479. continue;
  65480. }
  65481. $previousUnsetCall = $this->getPreviousUnsetCall($tokens, $index);
  65482. if (\is_int($previousUnsetCall)) {
  65483. $index = $previousUnsetCall;
  65484. continue;
  65485. }
  65486. [$previousUnset, , $previousUnsetBraceEnd] = $previousUnsetCall;
  65487. $tokensAddCount = $this->moveTokens(
  65488. $tokens,
  65489. $nextUnsetContentStart = $tokens->getNextTokenOfKind($index, ['(']),
  65490. $nextUnsetContentEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextUnsetContentStart),
  65491. $previousUnsetBraceEnd - 1
  65492. );
  65493. if (!$tokens[$previousUnsetBraceEnd]->isWhitespace()) {
  65494. $tokens->insertAt($previousUnsetBraceEnd, new Token([T_WHITESPACE, ' ']));
  65495. ++$tokensAddCount;
  65496. }
  65497. $tokens->insertAt($previousUnsetBraceEnd, new Token(','));
  65498. ++$tokensAddCount;
  65499. $this->clearOffsetTokens($tokens, $tokensAddCount, [$index, $nextUnsetContentStart, $nextUnsetContentEnd]);
  65500. $nextUnsetSemicolon = $tokens->getNextMeaningfulToken($nextUnsetContentEnd);
  65501. if (null !== $nextUnsetSemicolon && $tokens[$nextUnsetSemicolon]->equals(';')) {
  65502. $tokens->clearTokenAndMergeSurroundingWhitespace($nextUnsetSemicolon);
  65503. }
  65504. $index = $previousUnset + 1;
  65505. }
  65506. }
  65507. private function clearOffsetTokens(Tokens $tokens, int $offset, array $indices): void
  65508. {
  65509. foreach ($indices as $index) {
  65510. $tokens->clearTokenAndMergeSurroundingWhitespace($index + $offset);
  65511. }
  65512. }
  65513. private function getPreviousUnsetCall(Tokens $tokens, int $index)
  65514. {
  65515. $previousUnsetSemicolon = $tokens->getPrevMeaningfulToken($index);
  65516. if (null === $previousUnsetSemicolon) {
  65517. return $index;
  65518. }
  65519. if (!$tokens[$previousUnsetSemicolon]->equals(';')) {
  65520. return $previousUnsetSemicolon;
  65521. }
  65522. $previousUnsetBraceEnd = $tokens->getPrevMeaningfulToken($previousUnsetSemicolon);
  65523. if (null === $previousUnsetBraceEnd) {
  65524. return $index;
  65525. }
  65526. if (!$tokens[$previousUnsetBraceEnd]->equals(')')) {
  65527. return $previousUnsetBraceEnd;
  65528. }
  65529. $previousUnsetBraceStart = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $previousUnsetBraceEnd);
  65530. $previousUnset = $tokens->getPrevMeaningfulToken($previousUnsetBraceStart);
  65531. if (null === $previousUnset) {
  65532. return $index;
  65533. }
  65534. if (!$tokens[$previousUnset]->isGivenKind(T_UNSET)) {
  65535. return $previousUnset;
  65536. }
  65537. return [
  65538. $previousUnset,
  65539. $previousUnsetBraceStart,
  65540. $previousUnsetBraceEnd,
  65541. $previousUnsetSemicolon,
  65542. ];
  65543. }
  65544. private function moveTokens(Tokens $tokens, int $start, int $end, int $to): int
  65545. {
  65546. $added = 0;
  65547. for ($i = $start + 1; $i < $end; $i += 2) {
  65548. if ($tokens[$i]->isWhitespace() && $tokens[$to + 1]->isWhitespace()) {
  65549. $tokens[$to + 1] = new Token([T_WHITESPACE, $tokens[$to + 1]->getContent().$tokens[$i]->getContent()]);
  65550. } else {
  65551. $tokens->insertAt(++$to, clone $tokens[$i]);
  65552. ++$end;
  65553. ++$added;
  65554. }
  65555. $tokens->clearAt($i + 1);
  65556. }
  65557. return $added;
  65558. }
  65559. }
  65560. <?php
  65561. declare(strict_types=1);
  65562. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65563. use PhpCsFixer\AbstractFunctionReferenceFixer;
  65564. use PhpCsFixer\FixerDefinition\CodeSample;
  65565. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65566. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65567. use PhpCsFixer\Tokenizer\Token;
  65568. use PhpCsFixer\Tokenizer\Tokens;
  65569. final class DirConstantFixer extends AbstractFunctionReferenceFixer
  65570. {
  65571. public function getDefinition(): FixerDefinitionInterface
  65572. {
  65573. return new FixerDefinition(
  65574. 'Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.',
  65575. [new CodeSample("<?php\n\$a = dirname(__FILE__);\n")],
  65576. null,
  65577. 'Risky when the function `dirname` is overridden.'
  65578. );
  65579. }
  65580. public function isCandidate(Tokens $tokens): bool
  65581. {
  65582. return $tokens->isAllTokenKindsFound([T_STRING, T_FILE]);
  65583. }
  65584. public function getPriority(): int
  65585. {
  65586. return 40;
  65587. }
  65588. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65589. {
  65590. $currIndex = 0;
  65591. do {
  65592. $boundaries = $this->find('dirname', $tokens, $currIndex, $tokens->count() - 1);
  65593. if (null === $boundaries) {
  65594. return;
  65595. }
  65596. [$functionNameIndex, $openParenthesis, $closeParenthesis] = $boundaries;
  65597. $currIndex = $openParenthesis;
  65598. $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($closeParenthesis);
  65599. $trailingCommaIndex = null;
  65600. if ($tokens[$fileCandidateRightIndex]->equals(',')) {
  65601. $trailingCommaIndex = $fileCandidateRightIndex;
  65602. $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($fileCandidateRightIndex);
  65603. }
  65604. $fileCandidateRight = $tokens[$fileCandidateRightIndex];
  65605. if (!$fileCandidateRight->isGivenKind(T_FILE)) {
  65606. continue;
  65607. }
  65608. $fileCandidateLeftIndex = $tokens->getNextMeaningfulToken($openParenthesis);
  65609. $fileCandidateLeft = $tokens[$fileCandidateLeftIndex];
  65610. if (!$fileCandidateLeft->isGivenKind(T_FILE)) {
  65611. continue;
  65612. }
  65613. $namespaceCandidateIndex = $tokens->getPrevMeaningfulToken($functionNameIndex);
  65614. $namespaceCandidate = $tokens[$namespaceCandidateIndex];
  65615. if ($namespaceCandidate->isGivenKind(T_NS_SEPARATOR)) {
  65616. $tokens->removeTrailingWhitespace($namespaceCandidateIndex);
  65617. $tokens->clearAt($namespaceCandidateIndex);
  65618. }
  65619. if (null !== $trailingCommaIndex) {
  65620. if (!$tokens[$tokens->getNextNonWhitespace($trailingCommaIndex)]->isComment()) {
  65621. $tokens->removeTrailingWhitespace($trailingCommaIndex);
  65622. }
  65623. $tokens->clearTokenAndMergeSurroundingWhitespace($trailingCommaIndex);
  65624. }
  65625. if (!$tokens[$tokens->getNextNonWhitespace($closeParenthesis)]->isComment()) {
  65626. $tokens->removeLeadingWhitespace($closeParenthesis);
  65627. }
  65628. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesis);
  65629. if (!$tokens[$tokens->getNextNonWhitespace($openParenthesis)]->isComment()) {
  65630. $tokens->removeLeadingWhitespace($openParenthesis);
  65631. }
  65632. $tokens->removeTrailingWhitespace($openParenthesis);
  65633. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesis);
  65634. $tokens[$fileCandidateLeftIndex] = new Token([T_DIR, '__DIR__']);
  65635. $tokens->clearTokenAndMergeSurroundingWhitespace($functionNameIndex);
  65636. } while (null !== $currIndex);
  65637. }
  65638. }
  65639. <?php
  65640. declare(strict_types=1);
  65641. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65642. use PhpCsFixer\AbstractFixer;
  65643. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  65644. use PhpCsFixer\FixerDefinition\CodeSample;
  65645. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65646. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65647. use PhpCsFixer\Tokenizer\CT;
  65648. use PhpCsFixer\Tokenizer\Token;
  65649. use PhpCsFixer\Tokenizer\Tokens;
  65650. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  65651. final class ClassKeywordRemoveFixer extends AbstractFixer implements DeprecatedFixerInterface
  65652. {
  65653. private array $imports = [];
  65654. public function getDefinition(): FixerDefinitionInterface
  65655. {
  65656. return new FixerDefinition(
  65657. 'Converts `::class` keywords to FQCN strings.',
  65658. [
  65659. new CodeSample(
  65660. '<?php
  65661. use Foo\Bar\Baz;
  65662. $className = Baz::class;
  65663. '
  65664. ),
  65665. ]
  65666. );
  65667. }
  65668. public function getSuccessorsNames(): array
  65669. {
  65670. return [];
  65671. }
  65672. public function getPriority(): int
  65673. {
  65674. return 0;
  65675. }
  65676. public function isCandidate(Tokens $tokens): bool
  65677. {
  65678. return $tokens->isTokenKindFound(CT::T_CLASS_CONSTANT);
  65679. }
  65680. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65681. {
  65682. $previousNamespaceScopeEndIndex = 0;
  65683. foreach ($tokens->getNamespaceDeclarations() as $declaration) {
  65684. $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $declaration->getStartIndex());
  65685. $this->replaceClassKeywordsSection($tokens, $declaration->getFullName(), $declaration->getStartIndex(), $declaration->getScopeEndIndex());
  65686. $previousNamespaceScopeEndIndex = $declaration->getScopeEndIndex();
  65687. }
  65688. $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $tokens->count() - 1);
  65689. }
  65690. private function storeImports(Tokens $tokens, int $startIndex, int $endIndex): void
  65691. {
  65692. $tokensAnalyzer = new TokensAnalyzer($tokens);
  65693. $this->imports = [];
  65694. foreach ($tokensAnalyzer->getImportUseIndexes() as $index) {
  65695. if ($index < $startIndex || $index > $endIndex) {
  65696. continue;
  65697. }
  65698. $import = '';
  65699. while (($index = $tokens->getNextMeaningfulToken($index)) !== null) {
  65700. if ($tokens[$index]->equalsAny([';', [CT::T_GROUP_IMPORT_BRACE_OPEN]]) || $tokens[$index]->isGivenKind(T_AS)) {
  65701. break;
  65702. }
  65703. $import .= $tokens[$index]->getContent();
  65704. }
  65705. if ($tokens[$index]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  65706. $groupEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $index);
  65707. $groupImports = array_map(
  65708. static fn (string $import): string => trim($import),
  65709. explode(',', $tokens->generatePartialCode($index + 1, $groupEndIndex - 1))
  65710. );
  65711. foreach ($groupImports as $groupImport) {
  65712. $groupImportParts = array_map(static fn (string $import): string => trim($import), explode(' as ', $groupImport));
  65713. if (2 === \count($groupImportParts)) {
  65714. $this->imports[$groupImportParts[1]] = $import.$groupImportParts[0];
  65715. } else {
  65716. $this->imports[] = $import.$groupImport;
  65717. }
  65718. }
  65719. } elseif ($tokens[$index]->isGivenKind(T_AS)) {
  65720. $aliasIndex = $tokens->getNextMeaningfulToken($index);
  65721. $alias = $tokens[$aliasIndex]->getContent();
  65722. $this->imports[$alias] = $import;
  65723. } else {
  65724. $this->imports[] = $import;
  65725. }
  65726. }
  65727. }
  65728. private function replaceClassKeywordsSection(Tokens $tokens, string $namespace, int $startIndex, int $endIndex): void
  65729. {
  65730. if ($endIndex - $startIndex < 3) {
  65731. return;
  65732. }
  65733. $this->storeImports($tokens, $startIndex, $endIndex);
  65734. $ctClassTokens = $tokens->findGivenKind(CT::T_CLASS_CONSTANT, $startIndex, $endIndex);
  65735. foreach (array_reverse(array_keys($ctClassTokens)) as $classIndex) {
  65736. $this->replaceClassKeyword($tokens, $namespace, $classIndex);
  65737. }
  65738. }
  65739. private function replaceClassKeyword(Tokens $tokens, string $namespacePrefix, int $classIndex): void
  65740. {
  65741. $classEndIndex = $tokens->getPrevMeaningfulToken($classIndex);
  65742. $classEndIndex = $tokens->getPrevMeaningfulToken($classEndIndex);
  65743. if (!$tokens[$classEndIndex]->isGivenKind(T_STRING)) {
  65744. return;
  65745. }
  65746. if ($tokens[$classEndIndex]->equalsAny([[T_STRING, 'self'], [T_STATIC, 'static'], [T_STRING, 'parent']], false)) {
  65747. return;
  65748. }
  65749. $classBeginIndex = $classEndIndex;
  65750. while (true) {
  65751. $prev = $tokens->getPrevMeaningfulToken($classBeginIndex);
  65752. if (!$tokens[$prev]->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  65753. break;
  65754. }
  65755. $classBeginIndex = $prev;
  65756. }
  65757. $classString = $tokens->generatePartialCode(
  65758. $tokens[$classBeginIndex]->isGivenKind(T_NS_SEPARATOR)
  65759. ? $tokens->getNextMeaningfulToken($classBeginIndex)
  65760. : $classBeginIndex,
  65761. $classEndIndex
  65762. );
  65763. $classImport = false;
  65764. if ($tokens[$classBeginIndex]->isGivenKind(T_NS_SEPARATOR)) {
  65765. $namespacePrefix = '';
  65766. } else {
  65767. foreach ($this->imports as $alias => $import) {
  65768. if ($classString === $alias) {
  65769. $classImport = $import;
  65770. break;
  65771. }
  65772. $classStringArray = explode('\\', $classString);
  65773. $namespaceToTest = $classStringArray[0];
  65774. if (0 === ($namespaceToTest <=> substr($import, -\strlen($namespaceToTest)))) {
  65775. $classImport = $import;
  65776. break;
  65777. }
  65778. }
  65779. }
  65780. for ($i = $classBeginIndex; $i <= $classIndex; ++$i) {
  65781. if (!$tokens[$i]->isComment() && !($tokens[$i]->isWhitespace() && str_contains($tokens[$i]->getContent(), "\n"))) {
  65782. $tokens->clearAt($i);
  65783. }
  65784. }
  65785. $tokens->insertAt($classBeginIndex, new Token([
  65786. T_CONSTANT_ENCAPSED_STRING,
  65787. "'".$this->makeClassFQN($namespacePrefix, $classImport, $classString)."'",
  65788. ]));
  65789. }
  65790. private function makeClassFQN(string $namespacePrefix, $classImport, string $classString): string
  65791. {
  65792. if (false === $classImport) {
  65793. return ('' !== $namespacePrefix ? ($namespacePrefix.'\\') : '').$classString;
  65794. }
  65795. $classStringArray = explode('\\', $classString);
  65796. $classStringLength = \count($classStringArray);
  65797. $classImportArray = explode('\\', $classImport);
  65798. $classImportLength = \count($classImportArray);
  65799. if (1 === $classStringLength) {
  65800. return $classImport;
  65801. }
  65802. return implode('\\', array_merge(
  65803. \array_slice($classImportArray, 0, $classImportLength - $classStringLength + 1),
  65804. $classStringArray
  65805. ));
  65806. }
  65807. }
  65808. <?php
  65809. declare(strict_types=1);
  65810. namespace PhpCsFixer\Fixer\LanguageConstruct;
  65811. use PhpCsFixer\AbstractFixer;
  65812. use PhpCsFixer\FixerDefinition\CodeSample;
  65813. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65814. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65815. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  65816. use PhpCsFixer\Tokenizer\Token;
  65817. use PhpCsFixer\Tokenizer\Tokens;
  65818. /**
  65819. @phpstan-type
  65820. */
  65821. final class NoUnsetOnPropertyFixer extends AbstractFixer
  65822. {
  65823. public function getDefinition(): FixerDefinitionInterface
  65824. {
  65825. return new FixerDefinition(
  65826. 'Properties should be set to `null` instead of using `unset`.',
  65827. [new CodeSample("<?php\nunset(\$this->a);\n")],
  65828. null,
  65829. 'Risky when relying on attributes to be removed using `unset` rather than be set to `null`.'
  65830. .' Changing variables to `null` instead of unsetting means these still show up when looping over class variables'
  65831. .' and reference properties remain unbroken.'
  65832. .' With PHP 7.4, this rule might introduce `null` assignments to properties whose type declaration does not allow it.'
  65833. );
  65834. }
  65835. public function isRisky(): bool
  65836. {
  65837. return true;
  65838. }
  65839. public function isCandidate(Tokens $tokens): bool
  65840. {
  65841. return $tokens->isTokenKindFound(T_UNSET)
  65842. && $tokens->isAnyTokenKindsFound([T_OBJECT_OPERATOR, T_PAAMAYIM_NEKUDOTAYIM]);
  65843. }
  65844. public function getPriority(): int
  65845. {
  65846. return 25;
  65847. }
  65848. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  65849. {
  65850. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  65851. if (!$tokens[$index]->isGivenKind(T_UNSET)) {
  65852. continue;
  65853. }
  65854. $unsetsInfo = $this->getUnsetsInfo($tokens, $index);
  65855. if (!$this->isAnyUnsetToTransform($unsetsInfo)) {
  65856. continue;
  65857. }
  65858. $isLastUnset = true;
  65859. foreach (array_reverse($unsetsInfo) as $unsetInfo) {
  65860. $this->updateTokens($tokens, $unsetInfo, $isLastUnset);
  65861. $isLastUnset = false;
  65862. }
  65863. }
  65864. }
  65865. private function getUnsetsInfo(Tokens $tokens, int $index): array
  65866. {
  65867. $argumentsAnalyzer = new ArgumentsAnalyzer();
  65868. $unsetStart = $tokens->getNextTokenOfKind($index, ['(']);
  65869. $unsetEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $unsetStart);
  65870. $isFirst = true;
  65871. $unsets = [];
  65872. foreach ($argumentsAnalyzer->getArguments($tokens, $unsetStart, $unsetEnd) as $startIndex => $endIndex) {
  65873. $startIndex = $tokens->getNextMeaningfulToken($startIndex - 1);
  65874. $endIndex = $tokens->getPrevMeaningfulToken($endIndex + 1);
  65875. $unsets[] = [
  65876. 'startIndex' => $startIndex,
  65877. 'endIndex' => $endIndex,
  65878. 'isToTransform' => $this->isProperty($tokens, $startIndex, $endIndex),
  65879. 'isFirst' => $isFirst,
  65880. ];
  65881. $isFirst = false;
  65882. }
  65883. return $unsets;
  65884. }
  65885. private function isProperty(Tokens $tokens, int $index, int $endIndex): bool
  65886. {
  65887. if ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  65888. $nextIndex = $tokens->getNextMeaningfulToken($index);
  65889. if (null === $nextIndex || !$tokens[$nextIndex]->isGivenKind(T_OBJECT_OPERATOR)) {
  65890. return false;
  65891. }
  65892. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  65893. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  65894. if (null !== $nextNextIndex && $nextNextIndex < $endIndex) {
  65895. return false;
  65896. }
  65897. return null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(T_STRING);
  65898. }
  65899. if ($tokens[$index]->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  65900. $nextIndex = $tokens->getTokenNotOfKindsSibling($index, 1, [T_DOUBLE_COLON, T_NS_SEPARATOR, T_STRING]);
  65901. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  65902. if (null !== $nextNextIndex && $nextNextIndex < $endIndex) {
  65903. return false;
  65904. }
  65905. return null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(T_VARIABLE);
  65906. }
  65907. return false;
  65908. }
  65909. private function isAnyUnsetToTransform(array $unsetsInfo): bool
  65910. {
  65911. foreach ($unsetsInfo as $unsetInfo) {
  65912. if ($unsetInfo['isToTransform']) {
  65913. return true;
  65914. }
  65915. }
  65916. return false;
  65917. }
  65918. private function updateTokens(Tokens $tokens, array $unsetInfo, bool $isLastUnset): void
  65919. {
  65920. if ($unsetInfo['isFirst'] && $unsetInfo['isToTransform']) {
  65921. $braceIndex = $tokens->getPrevTokenOfKind($unsetInfo['startIndex'], ['(']);
  65922. $unsetIndex = $tokens->getPrevTokenOfKind($braceIndex, [[T_UNSET]]);
  65923. $tokens->clearTokenAndMergeSurroundingWhitespace($braceIndex);
  65924. $tokens->clearTokenAndMergeSurroundingWhitespace($unsetIndex);
  65925. }
  65926. if ($isLastUnset && $unsetInfo['isToTransform']) {
  65927. $braceIndex = $tokens->getNextTokenOfKind($unsetInfo['endIndex'], [')']);
  65928. $previousIndex = $tokens->getPrevMeaningfulToken($braceIndex);
  65929. if ($tokens[$previousIndex]->equals(',')) {
  65930. $tokens->clearTokenAndMergeSurroundingWhitespace($previousIndex);
  65931. }
  65932. $tokens->clearTokenAndMergeSurroundingWhitespace($braceIndex);
  65933. }
  65934. if (!$isLastUnset) {
  65935. $commaIndex = $tokens->getNextTokenOfKind($unsetInfo['endIndex'], [',']);
  65936. $tokens[$commaIndex] = new Token(';');
  65937. }
  65938. if (!$unsetInfo['isToTransform'] && !$isLastUnset) {
  65939. $tokens->insertAt($unsetInfo['endIndex'] + 1, new Token(')'));
  65940. }
  65941. if (!$unsetInfo['isToTransform'] && !$unsetInfo['isFirst']) {
  65942. $tokens->insertAt(
  65943. $unsetInfo['startIndex'],
  65944. [
  65945. new Token([T_UNSET, 'unset']),
  65946. new Token('('),
  65947. ]
  65948. );
  65949. }
  65950. if ($unsetInfo['isToTransform']) {
  65951. $tokens->insertAt(
  65952. $unsetInfo['endIndex'] + 1,
  65953. [
  65954. new Token([T_WHITESPACE, ' ']),
  65955. new Token('='),
  65956. new Token([T_WHITESPACE, ' ']),
  65957. new Token([T_STRING, 'null']),
  65958. ]
  65959. );
  65960. }
  65961. }
  65962. }
  65963. <?php
  65964. declare(strict_types=1);
  65965. namespace PhpCsFixer\Fixer\Alias;
  65966. use PhpCsFixer\AbstractFixer;
  65967. use PhpCsFixer\FixerDefinition\CodeSample;
  65968. use PhpCsFixer\FixerDefinition\FixerDefinition;
  65969. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  65970. use PhpCsFixer\Preg;
  65971. use PhpCsFixer\Tokenizer\Token;
  65972. use PhpCsFixer\Tokenizer\Tokens;
  65973. final class BacktickToShellExecFixer extends AbstractFixer
  65974. {
  65975. public function isCandidate(Tokens $tokens): bool
  65976. {
  65977. return $tokens->isTokenKindFound('`');
  65978. }
  65979. public function getDefinition(): FixerDefinitionInterface
  65980. {
  65981. return new FixerDefinition(
  65982. 'Converts backtick operators to `shell_exec` calls.',
  65983. [
  65984. new CodeSample(
  65985. <<<'EOT'
  65986. <?php
  65987. $plain = `ls -lah`;
  65988. $withVar = `ls -lah $var1 ${var2} {$var3} {$var4[0]} {$var5->call()}`;
  65989. EOT
  65990. ),
  65991. ],
  65992. 'Conversion is done only when it is non risky, so when special chars like single-quotes, double-quotes and backticks are not used inside the command.'
  65993. );
  65994. }
  65995. public function getPriority(): int
  65996. {
  65997. return 17;
  65998. }
  65999. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66000. {
  66001. $backtickStarted = false;
  66002. $backtickTokens = [];
  66003. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  66004. $token = $tokens[$index];
  66005. if (!$token->equals('`')) {
  66006. if ($backtickStarted) {
  66007. $backtickTokens[$index] = $token;
  66008. }
  66009. continue;
  66010. }
  66011. $backtickTokens[$index] = $token;
  66012. if ($backtickStarted) {
  66013. $this->fixBackticks($tokens, $backtickTokens);
  66014. $backtickTokens = [];
  66015. }
  66016. $backtickStarted = !$backtickStarted;
  66017. }
  66018. }
  66019. private function fixBackticks(Tokens $tokens, array $backtickTokens): void
  66020. {
  66021. ksort($backtickTokens);
  66022. $openingBacktickIndex = array_key_first($backtickTokens);
  66023. $closingBacktickIndex = array_key_last($backtickTokens);
  66024. array_shift($backtickTokens);
  66025. array_pop($backtickTokens);
  66026. $count = \count($backtickTokens);
  66027. $newTokens = [
  66028. new Token([T_STRING, 'shell_exec']),
  66029. new Token('('),
  66030. ];
  66031. if (1 !== $count) {
  66032. $newTokens[] = new Token('"');
  66033. }
  66034. foreach ($backtickTokens as $token) {
  66035. if (!$token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  66036. $newTokens[] = $token;
  66037. continue;
  66038. }
  66039. $content = $token->getContent();
  66040. if (Preg::match('/[`"\']/u', $content)) {
  66041. return;
  66042. }
  66043. $kind = T_ENCAPSED_AND_WHITESPACE;
  66044. if (1 === $count) {
  66045. $content = '"'.$content.'"';
  66046. $kind = T_CONSTANT_ENCAPSED_STRING;
  66047. }
  66048. $newTokens[] = new Token([$kind, $content]);
  66049. }
  66050. if (1 !== $count) {
  66051. $newTokens[] = new Token('"');
  66052. }
  66053. $newTokens[] = new Token(')');
  66054. $tokens->overrideRange($openingBacktickIndex, $closingBacktickIndex, $newTokens);
  66055. }
  66056. }
  66057. <?php
  66058. declare(strict_types=1);
  66059. namespace PhpCsFixer\Fixer\Alias;
  66060. use PhpCsFixer\AbstractFixer;
  66061. use PhpCsFixer\FixerDefinition\CodeSample;
  66062. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66063. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66064. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  66065. use PhpCsFixer\Tokenizer\CT;
  66066. use PhpCsFixer\Tokenizer\Token;
  66067. use PhpCsFixer\Tokenizer\Tokens;
  66068. final class ArrayPushFixer extends AbstractFixer
  66069. {
  66070. public function getDefinition(): FixerDefinitionInterface
  66071. {
  66072. return new FixerDefinition(
  66073. 'Converts simple usages of `array_push($x, $y);` to `$x[] = $y;`.',
  66074. [new CodeSample("<?php\narray_push(\$x, \$y);\n")],
  66075. null,
  66076. 'Risky when the function `array_push` is overridden.'
  66077. );
  66078. }
  66079. public function isCandidate(Tokens $tokens): bool
  66080. {
  66081. return $tokens->isTokenKindFound(T_STRING) && $tokens->count() > 7;
  66082. }
  66083. public function isRisky(): bool
  66084. {
  66085. return true;
  66086. }
  66087. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66088. {
  66089. $functionsAnalyzer = new FunctionsAnalyzer();
  66090. for ($index = $tokens->count() - 7; $index > 0; --$index) {
  66091. if (!$tokens[$index]->equals([T_STRING, 'array_push'], false)) {
  66092. continue;
  66093. }
  66094. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  66095. continue;
  66096. }
  66097. $callIndex = $index;
  66098. $index = $tokens->getPrevMeaningfulToken($index);
  66099. $namespaceSeparatorIndex = null;
  66100. if ($tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  66101. $namespaceSeparatorIndex = $index;
  66102. $index = $tokens->getPrevMeaningfulToken($index);
  66103. }
  66104. if (!$tokens[$index]->equalsAny([';', '{', '}', ')', [T_OPEN_TAG]])) {
  66105. continue;
  66106. }
  66107. $openBraceIndex = $tokens->getNextMeaningfulToken($callIndex);
  66108. $blockType = Tokens::detectBlockType($tokens[$openBraceIndex]);
  66109. if (null === $blockType || Tokens::BLOCK_TYPE_PARENTHESIS_BRACE !== $blockType['type']) {
  66110. continue;
  66111. }
  66112. $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBraceIndex);
  66113. $afterCloseBraceIndex = $tokens->getNextMeaningfulToken($closeBraceIndex);
  66114. if (null !== $afterCloseBraceIndex && !$tokens[$afterCloseBraceIndex]->equalsAny([';', [T_CLOSE_TAG]])) {
  66115. continue;
  66116. }
  66117. $firstArgumentStop = $this->getFirstArgumentEnd($tokens, $openBraceIndex);
  66118. $firstArgumentStop = $tokens->getNextMeaningfulToken($firstArgumentStop);
  66119. if (!$tokens[$firstArgumentStop]->equals(',')) {
  66120. return;
  66121. }
  66122. $secondArgumentStart = $tokens->getNextMeaningfulToken($firstArgumentStop);
  66123. $secondArgumentStop = $this->getSecondArgumentEnd($tokens, $secondArgumentStart, $closeBraceIndex);
  66124. if (null === $secondArgumentStop) {
  66125. continue;
  66126. }
  66127. $tokens->clearTokenAndMergeSurroundingWhitespace($closeBraceIndex);
  66128. $tokens->clearTokenAndMergeSurroundingWhitespace($firstArgumentStop);
  66129. $tokens->insertAt(
  66130. $firstArgumentStop,
  66131. [
  66132. new Token('['),
  66133. new Token(']'),
  66134. new Token([T_WHITESPACE, ' ']),
  66135. new Token('='),
  66136. ]
  66137. );
  66138. $tokens->clearTokenAndMergeSurroundingWhitespace($openBraceIndex);
  66139. $tokens->clearTokenAndMergeSurroundingWhitespace($callIndex);
  66140. if (null !== $namespaceSeparatorIndex) {
  66141. $tokens->clearTokenAndMergeSurroundingWhitespace($namespaceSeparatorIndex);
  66142. }
  66143. }
  66144. }
  66145. private function getFirstArgumentEnd(Tokens $tokens, int $index): int
  66146. {
  66147. $nextIndex = $tokens->getNextMeaningfulToken($index);
  66148. $nextToken = $tokens[$nextIndex];
  66149. while ($nextToken->equalsAny([
  66150. '$',
  66151. '[',
  66152. '(',
  66153. [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN],
  66154. [CT::T_DYNAMIC_PROP_BRACE_OPEN],
  66155. [CT::T_DYNAMIC_VAR_BRACE_OPEN],
  66156. [CT::T_NAMESPACE_OPERATOR],
  66157. [T_NS_SEPARATOR],
  66158. [T_STATIC],
  66159. [T_STRING],
  66160. [T_VARIABLE],
  66161. ])) {
  66162. $blockType = Tokens::detectBlockType($nextToken);
  66163. if (null !== $blockType) {
  66164. $nextIndex = $tokens->findBlockEnd($blockType['type'], $nextIndex);
  66165. }
  66166. $index = $nextIndex;
  66167. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  66168. $nextToken = $tokens[$nextIndex];
  66169. }
  66170. if ($nextToken->isGivenKind(T_OBJECT_OPERATOR)) {
  66171. return $this->getFirstArgumentEnd($tokens, $nextIndex);
  66172. }
  66173. if ($nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  66174. return $this->getFirstArgumentEnd($tokens, $tokens->getNextMeaningfulToken($nextIndex));
  66175. }
  66176. return $index;
  66177. }
  66178. private function getSecondArgumentEnd(Tokens $tokens, int $index, int $endIndex): ?int
  66179. {
  66180. if ($tokens[$index]->isGivenKind(T_ELLIPSIS)) {
  66181. return null;
  66182. }
  66183. for (; $index <= $endIndex; ++$index) {
  66184. $blockType = Tokens::detectBlockType($tokens[$index]);
  66185. while (null !== $blockType && $blockType['isStart']) {
  66186. $index = $tokens->findBlockEnd($blockType['type'], $index);
  66187. $index = $tokens->getNextMeaningfulToken($index);
  66188. $blockType = Tokens::detectBlockType($tokens[$index]);
  66189. }
  66190. if ($tokens[$index]->equals(',') || $tokens[$index]->isGivenKind([T_YIELD, T_YIELD_FROM, T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR])) {
  66191. return null;
  66192. }
  66193. }
  66194. return $endIndex;
  66195. }
  66196. }
  66197. <?php
  66198. declare(strict_types=1);
  66199. namespace PhpCsFixer\Fixer\Alias;
  66200. use PhpCsFixer\AbstractFunctionReferenceFixer;
  66201. use PhpCsFixer\FixerDefinition\CodeSample;
  66202. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66203. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66204. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  66205. use PhpCsFixer\Tokenizer\Token;
  66206. use PhpCsFixer\Tokenizer\Tokens;
  66207. final class SetTypeToCastFixer extends AbstractFunctionReferenceFixer
  66208. {
  66209. public function getDefinition(): FixerDefinitionInterface
  66210. {
  66211. return new FixerDefinition(
  66212. 'Cast shall be used, not `settype`.',
  66213. [
  66214. new CodeSample(
  66215. '<?php
  66216. settype($foo, "integer");
  66217. settype($bar, "string");
  66218. settype($bar, "null");
  66219. '
  66220. ),
  66221. ],
  66222. null,
  66223. 'Risky when the `settype` function is overridden or when used as the 2nd or 3rd expression in a `for` loop .'
  66224. );
  66225. }
  66226. public function getPriority(): int
  66227. {
  66228. return 0;
  66229. }
  66230. public function isCandidate(Tokens $tokens): bool
  66231. {
  66232. return $tokens->isAllTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_STRING, T_VARIABLE]);
  66233. }
  66234. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66235. {
  66236. $map = [
  66237. 'array' => [T_ARRAY_CAST, '(array)'],
  66238. 'bool' => [T_BOOL_CAST, '(bool)'],
  66239. 'boolean' => [T_BOOL_CAST, '(bool)'],
  66240. 'double' => [T_DOUBLE_CAST, '(float)'],
  66241. 'float' => [T_DOUBLE_CAST, '(float)'],
  66242. 'int' => [T_INT_CAST, '(int)'],
  66243. 'integer' => [T_INT_CAST, '(int)'],
  66244. 'object' => [T_OBJECT_CAST, '(object)'],
  66245. 'string' => [T_STRING_CAST, '(string)'],
  66246. ];
  66247. $argumentsAnalyzer = new ArgumentsAnalyzer();
  66248. foreach (array_reverse($this->findSettypeCalls($tokens)) as $candidate) {
  66249. $functionNameIndex = $candidate[0];
  66250. $arguments = $argumentsAnalyzer->getArguments($tokens, $candidate[1], $candidate[2]);
  66251. if (2 !== \count($arguments)) {
  66252. continue;
  66253. }
  66254. $prev = $tokens->getPrevMeaningfulToken($functionNameIndex);
  66255. if (!$tokens[$prev]->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
  66256. continue;
  66257. }
  66258. reset($arguments);
  66259. $firstArgumentStart = key($arguments);
  66260. if ($tokens[$firstArgumentStart]->isComment() || $tokens[$firstArgumentStart]->isWhitespace()) {
  66261. $firstArgumentStart = $tokens->getNextMeaningfulToken($firstArgumentStart);
  66262. }
  66263. if (!$tokens[$firstArgumentStart]->isGivenKind(T_VARIABLE)) {
  66264. continue;
  66265. }
  66266. $commaIndex = $tokens->getNextMeaningfulToken($firstArgumentStart);
  66267. if (null === $commaIndex || !$tokens[$commaIndex]->equals(',')) {
  66268. continue;
  66269. }
  66270. next($arguments);
  66271. $secondArgumentStart = key($arguments);
  66272. $secondArgumentEnd = $arguments[$secondArgumentStart];
  66273. if ($tokens[$secondArgumentStart]->isComment() || $tokens[$secondArgumentStart]->isWhitespace()) {
  66274. $secondArgumentStart = $tokens->getNextMeaningfulToken($secondArgumentStart);
  66275. }
  66276. if (
  66277. !$tokens[$secondArgumentStart]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)
  66278. || $tokens->getNextMeaningfulToken($secondArgumentStart) < $secondArgumentEnd
  66279. ) {
  66280. continue;
  66281. }
  66282. $type = strtolower(trim($tokens[$secondArgumentStart]->getContent(), '"\''));
  66283. if ('null' !== $type && !isset($map[$type])) {
  66284. continue;
  66285. }
  66286. $argumentToken = $tokens[$firstArgumentStart];
  66287. $this->removeSettypeCall(
  66288. $tokens,
  66289. $functionNameIndex,
  66290. $candidate[1],
  66291. $firstArgumentStart,
  66292. $commaIndex,
  66293. $secondArgumentStart,
  66294. $candidate[2]
  66295. );
  66296. if ('null' === $type) {
  66297. $this->fixSettypeNullCall($tokens, $functionNameIndex, $argumentToken);
  66298. } else {
  66299. $this->fixSettypeCall($tokens, $functionNameIndex, $argumentToken, new Token($map[$type]));
  66300. }
  66301. }
  66302. }
  66303. private function findSettypeCalls(Tokens $tokens): array
  66304. {
  66305. $candidates = [];
  66306. $end = \count($tokens);
  66307. for ($i = 1; $i < $end; ++$i) {
  66308. $candidate = $this->find('settype', $tokens, $i, $end);
  66309. if (null === $candidate) {
  66310. break;
  66311. }
  66312. $i = $candidate[1];
  66313. $candidates[] = $candidate;
  66314. }
  66315. return $candidates;
  66316. }
  66317. private function removeSettypeCall(
  66318. Tokens $tokens,
  66319. int $functionNameIndex,
  66320. int $openParenthesisIndex,
  66321. int $firstArgumentStart,
  66322. int $commaIndex,
  66323. int $secondArgumentStart,
  66324. int $closeParenthesisIndex
  66325. ): void {
  66326. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesisIndex);
  66327. $prevIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  66328. if ($tokens[$prevIndex]->equals(',')) {
  66329. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  66330. }
  66331. $tokens->clearTokenAndMergeSurroundingWhitespace($secondArgumentStart);
  66332. $tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
  66333. $tokens->clearTokenAndMergeSurroundingWhitespace($firstArgumentStart);
  66334. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesisIndex);
  66335. $tokens->clearAt($functionNameIndex);
  66336. $tokens->clearEmptyTokens();
  66337. }
  66338. private function fixSettypeCall(
  66339. Tokens $tokens,
  66340. int $functionNameIndex,
  66341. Token $argumentToken,
  66342. Token $castToken
  66343. ): void {
  66344. $tokens->insertAt(
  66345. $functionNameIndex,
  66346. [
  66347. clone $argumentToken,
  66348. new Token([T_WHITESPACE, ' ']),
  66349. new Token('='),
  66350. new Token([T_WHITESPACE, ' ']),
  66351. $castToken,
  66352. new Token([T_WHITESPACE, ' ']),
  66353. clone $argumentToken,
  66354. ]
  66355. );
  66356. $tokens->removeTrailingWhitespace($functionNameIndex + 6);
  66357. }
  66358. private function fixSettypeNullCall(
  66359. Tokens $tokens,
  66360. int $functionNameIndex,
  66361. Token $argumentToken
  66362. ): void {
  66363. $tokens->insertAt(
  66364. $functionNameIndex,
  66365. [
  66366. clone $argumentToken,
  66367. new Token([T_WHITESPACE, ' ']),
  66368. new Token('='),
  66369. new Token([T_WHITESPACE, ' ']),
  66370. new Token([T_STRING, 'null']),
  66371. ]
  66372. );
  66373. $tokens->removeTrailingWhitespace($functionNameIndex + 4);
  66374. }
  66375. }
  66376. <?php
  66377. declare(strict_types=1);
  66378. namespace PhpCsFixer\Fixer\Alias;
  66379. use PhpCsFixer\AbstractFunctionReferenceFixer;
  66380. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  66381. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  66382. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  66383. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  66384. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  66385. use PhpCsFixer\FixerDefinition\CodeSample;
  66386. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66387. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66388. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  66389. use PhpCsFixer\Tokenizer\Token;
  66390. use PhpCsFixer\Tokenizer\Tokens;
  66391. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  66392. /**
  66393. @phpstan-type
  66394. @phpstan-type
  66395. @implements
  66396. */
  66397. final class RandomApiMigrationFixer extends AbstractFunctionReferenceFixer implements ConfigurableFixerInterface
  66398. {
  66399. /**
  66400. @use */
  66401. use ConfigurableFixerTrait;
  66402. private const ARGUMENT_COUNTS = [
  66403. 'getrandmax' => [0],
  66404. 'mt_rand' => [1, 2],
  66405. 'rand' => [0, 2],
  66406. 'srand' => [0, 1],
  66407. 'random_int' => [0, 2],
  66408. ];
  66409. public function getDefinition(): FixerDefinitionInterface
  66410. {
  66411. return new FixerDefinition(
  66412. 'Replaces `rand`, `srand`, `getrandmax` functions calls with their `mt_*` analogs or `random_int`.',
  66413. [
  66414. new CodeSample("<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n"),
  66415. new CodeSample(
  66416. "<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n",
  66417. ['replacements' => ['getrandmax' => 'mt_getrandmax']]
  66418. ),
  66419. new CodeSample(
  66420. "<?php \$a = rand(\$b, \$c);\n",
  66421. ['replacements' => ['rand' => 'random_int']]
  66422. ),
  66423. ],
  66424. null,
  66425. 'Risky when the configured functions are overridden. Or when relying on the seed based generating of the numbers.'
  66426. );
  66427. }
  66428. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66429. {
  66430. $argumentsAnalyzer = new ArgumentsAnalyzer();
  66431. foreach ($this->configuration['replacements'] as $functionIdentity => $functionReplacement) {
  66432. if ($functionIdentity === $functionReplacement) {
  66433. continue;
  66434. }
  66435. $currIndex = 0;
  66436. do {
  66437. $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
  66438. if (null === $boundaries) {
  66439. continue 2;
  66440. }
  66441. [$functionName, $openParenthesis, $closeParenthesis] = $boundaries;
  66442. $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis);
  66443. \assert(isset(self::ARGUMENT_COUNTS[$functionIdentity]));
  66444. if (!\in_array($count, self::ARGUMENT_COUNTS[$functionIdentity], true)) {
  66445. continue 2;
  66446. }
  66447. $currIndex = $openParenthesis;
  66448. $tokens[$functionName] = new Token([T_STRING, $functionReplacement]);
  66449. if (0 === $count && 'random_int' === $functionReplacement) {
  66450. $tokens->insertAt($currIndex + 1, [
  66451. new Token([T_LNUMBER, '0']),
  66452. new Token(','),
  66453. new Token([T_WHITESPACE, ' ']),
  66454. new Token([T_STRING, 'getrandmax']),
  66455. new Token('('),
  66456. new Token(')'),
  66457. ]);
  66458. $currIndex += 6;
  66459. }
  66460. } while (null !== $currIndex);
  66461. }
  66462. }
  66463. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  66464. {
  66465. return new FixerConfigurationResolver([
  66466. (new FixerOptionBuilder('replacements', 'Mapping between replaced functions with the new ones.'))
  66467. ->setAllowedTypes(['array<string, string>'])
  66468. ->setAllowedValues([static function (array $value): bool {
  66469. foreach ($value as $functionName => $replacement) {
  66470. if (!\array_key_exists($functionName, self::ARGUMENT_COUNTS)) {
  66471. throw new InvalidOptionsException(\sprintf(
  66472. 'Function "%s" is not handled by the fixer.',
  66473. $functionName
  66474. ));
  66475. }
  66476. }
  66477. return true;
  66478. }])
  66479. ->setDefault([
  66480. 'getrandmax' => 'mt_getrandmax',
  66481. 'rand' => 'mt_rand',
  66482. 'srand' => 'mt_srand',
  66483. ])
  66484. ->getOption(),
  66485. ]);
  66486. }
  66487. }
  66488. <?php
  66489. declare(strict_types=1);
  66490. namespace PhpCsFixer\Fixer\Alias;
  66491. use PhpCsFixer\AbstractFixer;
  66492. use PhpCsFixer\FixerDefinition\CodeSample;
  66493. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66494. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66495. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  66496. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  66497. use PhpCsFixer\Tokenizer\CT;
  66498. use PhpCsFixer\Tokenizer\Token;
  66499. use PhpCsFixer\Tokenizer\Tokens;
  66500. final class MbStrFunctionsFixer extends AbstractFixer
  66501. {
  66502. private static array $functionsMap = [
  66503. 'str_split' => ['alternativeName' => 'mb_str_split', 'argumentCount' => [1, 2, 3]],
  66504. 'stripos' => ['alternativeName' => 'mb_stripos', 'argumentCount' => [2, 3]],
  66505. 'stristr' => ['alternativeName' => 'mb_stristr', 'argumentCount' => [2, 3]],
  66506. 'strlen' => ['alternativeName' => 'mb_strlen', 'argumentCount' => [1]],
  66507. 'strpos' => ['alternativeName' => 'mb_strpos', 'argumentCount' => [2, 3]],
  66508. 'strrchr' => ['alternativeName' => 'mb_strrchr', 'argumentCount' => [2]],
  66509. 'strripos' => ['alternativeName' => 'mb_strripos', 'argumentCount' => [2, 3]],
  66510. 'strrpos' => ['alternativeName' => 'mb_strrpos', 'argumentCount' => [2, 3]],
  66511. 'strstr' => ['alternativeName' => 'mb_strstr', 'argumentCount' => [2, 3]],
  66512. 'strtolower' => ['alternativeName' => 'mb_strtolower', 'argumentCount' => [1]],
  66513. 'strtoupper' => ['alternativeName' => 'mb_strtoupper', 'argumentCount' => [1]],
  66514. 'substr' => ['alternativeName' => 'mb_substr', 'argumentCount' => [2, 3]],
  66515. 'substr_count' => ['alternativeName' => 'mb_substr_count', 'argumentCount' => [2, 3, 4]],
  66516. ];
  66517. private array $functions;
  66518. public function __construct()
  66519. {
  66520. parent::__construct();
  66521. if (\PHP_VERSION_ID >= 8_03_00) {
  66522. self::$functionsMap['str_pad'] = ['alternativeName' => 'mb_str_pad', 'argumentCount' => [1, 2, 3, 4]];
  66523. }
  66524. if (\PHP_VERSION_ID >= 8_04_00) {
  66525. self::$functionsMap['trim'] = ['alternativeName' => 'mb_trim', 'argumentCount' => [1, 2]];
  66526. self::$functionsMap['ltrim'] = ['alternativeName' => 'mb_ltrim', 'argumentCount' => [1, 2]];
  66527. self::$functionsMap['rtrim'] = ['alternativeName' => 'mb_rtrim', 'argumentCount' => [1, 2]];
  66528. }
  66529. $this->functions = array_filter(
  66530. self::$functionsMap,
  66531. static fn (array $mapping): bool => (new \ReflectionFunction($mapping['alternativeName']))->isInternal()
  66532. );
  66533. }
  66534. public function isCandidate(Tokens $tokens): bool
  66535. {
  66536. return $tokens->isTokenKindFound(T_STRING);
  66537. }
  66538. public function isRisky(): bool
  66539. {
  66540. return true;
  66541. }
  66542. public function getPriority(): int
  66543. {
  66544. return 2;
  66545. }
  66546. public function getDefinition(): FixerDefinitionInterface
  66547. {
  66548. return new FixerDefinition(
  66549. 'Replace non multibyte-safe functions with corresponding mb function.',
  66550. [
  66551. new CodeSample(
  66552. '<?php
  66553. $a = strlen($a);
  66554. $a = strpos($a, $b);
  66555. $a = strrpos($a, $b);
  66556. $a = substr($a, $b);
  66557. $a = strtolower($a);
  66558. $a = strtoupper($a);
  66559. $a = stripos($a, $b);
  66560. $a = strripos($a, $b);
  66561. $a = strstr($a, $b);
  66562. $a = stristr($a, $b);
  66563. $a = strrchr($a, $b);
  66564. $a = substr_count($a, $b);
  66565. '
  66566. ),
  66567. ],
  66568. null,
  66569. 'Risky when any of the functions are overridden, or when relying on the string byte size rather than its length in characters.'
  66570. );
  66571. }
  66572. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66573. {
  66574. $argumentsAnalyzer = new ArgumentsAnalyzer();
  66575. $functionsAnalyzer = new FunctionsAnalyzer();
  66576. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  66577. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  66578. continue;
  66579. }
  66580. $lowercasedContent = strtolower($tokens[$index]->getContent());
  66581. if (!isset($this->functions[$lowercasedContent])) {
  66582. continue;
  66583. }
  66584. if ($functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  66585. $openParenthesis = $tokens->getNextMeaningfulToken($index);
  66586. $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
  66587. $numberOfArguments = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis);
  66588. if (!\in_array($numberOfArguments, $this->functions[$lowercasedContent]['argumentCount'], true)) {
  66589. continue;
  66590. }
  66591. $tokens[$index] = new Token([T_STRING, $this->functions[$lowercasedContent]['alternativeName']]);
  66592. continue;
  66593. }
  66594. $functionIndex = $tokens->getPrevMeaningfulToken($index);
  66595. if ($tokens[$functionIndex]->isGivenKind(T_NS_SEPARATOR)) {
  66596. $functionIndex = $tokens->getPrevMeaningfulToken($functionIndex);
  66597. }
  66598. if (!$tokens[$functionIndex]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  66599. continue;
  66600. }
  66601. $useIndex = $tokens->getPrevMeaningfulToken($functionIndex);
  66602. if (!$tokens[$useIndex]->isGivenKind(T_USE)) {
  66603. continue;
  66604. }
  66605. $tokens[$index] = new Token([T_STRING, $this->functions[$lowercasedContent]['alternativeName']]);
  66606. }
  66607. }
  66608. }
  66609. <?php
  66610. declare(strict_types=1);
  66611. namespace PhpCsFixer\Fixer\Alias;
  66612. use PhpCsFixer\AbstractFixer;
  66613. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  66614. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  66615. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  66616. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  66617. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  66618. use PhpCsFixer\FixerDefinition\CodeSample;
  66619. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66620. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66621. use PhpCsFixer\Tokenizer\CT;
  66622. use PhpCsFixer\Tokenizer\Token;
  66623. use PhpCsFixer\Tokenizer\Tokens;
  66624. /**
  66625. @phpstan-type
  66626. @phpstan-type
  66627. @implements
  66628. */
  66629. final class NoMixedEchoPrintFixer extends AbstractFixer implements ConfigurableFixerInterface
  66630. {
  66631. /**
  66632. @use */
  66633. use ConfigurableFixerTrait;
  66634. private int $candidateTokenType;
  66635. public function getDefinition(): FixerDefinitionInterface
  66636. {
  66637. return new FixerDefinition(
  66638. 'Either language construct `print` or `echo` should be used.',
  66639. [
  66640. new CodeSample("<?php print 'example';\n"),
  66641. new CodeSample("<?php echo('example');\n", ['use' => 'print']),
  66642. ]
  66643. );
  66644. }
  66645. public function getPriority(): int
  66646. {
  66647. return -10;
  66648. }
  66649. public function isCandidate(Tokens $tokens): bool
  66650. {
  66651. return $tokens->isTokenKindFound($this->candidateTokenType);
  66652. }
  66653. protected function configurePostNormalisation(): void
  66654. {
  66655. $this->candidateTokenType = 'echo' === $this->configuration['use'] ? T_PRINT : T_ECHO;
  66656. }
  66657. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66658. {
  66659. foreach ($tokens as $index => $token) {
  66660. if ($token->isGivenKind($this->candidateTokenType)) {
  66661. if (T_PRINT === $this->candidateTokenType) {
  66662. $this->fixPrintToEcho($tokens, $index);
  66663. } else {
  66664. $this->fixEchoToPrint($tokens, $index);
  66665. }
  66666. }
  66667. }
  66668. }
  66669. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  66670. {
  66671. return new FixerConfigurationResolver([
  66672. (new FixerOptionBuilder('use', 'The desired language construct.'))
  66673. ->setAllowedValues(['print', 'echo'])
  66674. ->setDefault('echo')
  66675. ->getOption(),
  66676. ]);
  66677. }
  66678. private function fixEchoToPrint(Tokens $tokens, int $index): void
  66679. {
  66680. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  66681. $endTokenIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  66682. $canBeConverted = true;
  66683. for ($i = $nextTokenIndex; $i < $endTokenIndex; ++$i) {
  66684. if ($tokens[$i]->equalsAny(['(', [CT::T_ARRAY_SQUARE_BRACE_OPEN]])) {
  66685. $blockType = Tokens::detectBlockType($tokens[$i]);
  66686. $i = $tokens->findBlockEnd($blockType['type'], $i);
  66687. }
  66688. if ($tokens[$i]->equals(',')) {
  66689. $canBeConverted = false;
  66690. break;
  66691. }
  66692. }
  66693. if (false === $canBeConverted) {
  66694. return;
  66695. }
  66696. $tokens[$index] = new Token([T_PRINT, 'print']);
  66697. }
  66698. private function fixPrintToEcho(Tokens $tokens, int $index): void
  66699. {
  66700. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  66701. if (!$prevToken->equalsAny([';', '{', '}', ')', [T_OPEN_TAG], [T_ELSE]])) {
  66702. return;
  66703. }
  66704. $tokens[$index] = new Token([T_ECHO, 'echo']);
  66705. }
  66706. }
  66707. <?php
  66708. declare(strict_types=1);
  66709. namespace PhpCsFixer\Fixer\Alias;
  66710. use PhpCsFixer\AbstractFixer;
  66711. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  66712. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  66713. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  66714. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  66715. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  66716. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  66717. use PhpCsFixer\FixerDefinition\CodeSample;
  66718. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66719. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66720. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  66721. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  66722. use PhpCsFixer\Tokenizer\Token;
  66723. use PhpCsFixer\Tokenizer\Tokens;
  66724. /**
  66725. @phpstan-type
  66726. @phpstan-type
  66727. @implements
  66728. */
  66729. final class NoAliasFunctionsFixer extends AbstractFixer implements ConfigurableFixerInterface
  66730. {
  66731. /**
  66732. @use */
  66733. use ConfigurableFixerTrait;
  66734. private const SETS = [
  66735. '@internal' => [
  66736. 'diskfreespace' => 'disk_free_space',
  66737. 'dns_check_record' => 'checkdnsrr',
  66738. 'dns_get_mx' => 'getmxrr',
  66739. 'session_commit' => 'session_write_close',
  66740. 'stream_register_wrapper' => 'stream_wrapper_register',
  66741. 'set_file_buffer' => 'stream_set_write_buffer',
  66742. 'socket_set_blocking' => 'stream_set_blocking',
  66743. 'socket_get_status' => 'stream_get_meta_data',
  66744. 'socket_set_timeout' => 'stream_set_timeout',
  66745. 'socket_getopt' => 'socket_get_option',
  66746. 'socket_setopt' => 'socket_set_option',
  66747. 'chop' => 'rtrim',
  66748. 'close' => 'closedir',
  66749. 'doubleval' => 'floatval',
  66750. 'fputs' => 'fwrite',
  66751. 'get_required_files' => 'get_included_files',
  66752. 'ini_alter' => 'ini_set',
  66753. 'is_double' => 'is_float',
  66754. 'is_integer' => 'is_int',
  66755. 'is_long' => 'is_int',
  66756. 'is_real' => 'is_float',
  66757. 'is_writeable' => 'is_writable',
  66758. 'join' => 'implode',
  66759. 'key_exists' => 'array_key_exists',
  66760. 'magic_quotes_runtime' => 'set_magic_quotes_runtime',
  66761. 'pos' => 'current',
  66762. 'show_source' => 'highlight_file',
  66763. 'sizeof' => 'count',
  66764. 'strchr' => 'strstr',
  66765. 'user_error' => 'trigger_error',
  66766. ],
  66767. '@IMAP' => [
  66768. 'imap_create' => 'imap_createmailbox',
  66769. 'imap_fetchtext' => 'imap_body',
  66770. 'imap_header' => 'imap_headerinfo',
  66771. 'imap_listmailbox' => 'imap_list',
  66772. 'imap_listsubscribed' => 'imap_lsub',
  66773. 'imap_rename' => 'imap_renamemailbox',
  66774. 'imap_scan' => 'imap_listscan',
  66775. 'imap_scanmailbox' => 'imap_listscan',
  66776. ],
  66777. '@ldap' => [
  66778. 'ldap_close' => 'ldap_unbind',
  66779. 'ldap_modify' => 'ldap_mod_replace',
  66780. ],
  66781. '@mysqli' => [
  66782. 'mysqli_execute' => 'mysqli_stmt_execute',
  66783. 'mysqli_set_opt' => 'mysqli_options',
  66784. 'mysqli_escape_string' => 'mysqli_real_escape_string',
  66785. ],
  66786. '@pg' => [
  66787. 'pg_exec' => 'pg_query',
  66788. ],
  66789. '@oci' => [
  66790. 'oci_free_cursor' => 'oci_free_statement',
  66791. ],
  66792. '@odbc' => [
  66793. 'odbc_do' => 'odbc_exec',
  66794. 'odbc_field_precision' => 'odbc_field_len',
  66795. ],
  66796. '@mbreg' => [
  66797. 'mbereg' => 'mb_ereg',
  66798. 'mbereg_match' => 'mb_ereg_match',
  66799. 'mbereg_replace' => 'mb_ereg_replace',
  66800. 'mbereg_search' => 'mb_ereg_search',
  66801. 'mbereg_search_getpos' => 'mb_ereg_search_getpos',
  66802. 'mbereg_search_getregs' => 'mb_ereg_search_getregs',
  66803. 'mbereg_search_init' => 'mb_ereg_search_init',
  66804. 'mbereg_search_pos' => 'mb_ereg_search_pos',
  66805. 'mbereg_search_regs' => 'mb_ereg_search_regs',
  66806. 'mbereg_search_setpos' => 'mb_ereg_search_setpos',
  66807. 'mberegi' => 'mb_eregi',
  66808. 'mberegi_replace' => 'mb_eregi_replace',
  66809. 'mbregex_encoding' => 'mb_regex_encoding',
  66810. 'mbsplit' => 'mb_split',
  66811. ],
  66812. '@openssl' => [
  66813. 'openssl_get_publickey' => 'openssl_pkey_get_public',
  66814. 'openssl_get_privatekey' => 'openssl_pkey_get_private',
  66815. ],
  66816. '@sodium' => [
  66817. 'sodium_crypto_scalarmult_base' => 'sodium_crypto_box_publickey_from_secretkey',
  66818. ],
  66819. '@exif' => [
  66820. 'read_exif_data' => 'exif_read_data',
  66821. ],
  66822. '@ftp' => [
  66823. 'ftp_quit' => 'ftp_close',
  66824. ],
  66825. '@posix' => [
  66826. 'posix_errno' => 'posix_get_last_error',
  66827. ],
  66828. '@pcntl' => [
  66829. 'pcntl_errno' => 'pcntl_get_last_error',
  66830. ],
  66831. '@time' => [
  66832. 'mktime' => ['time', 0],
  66833. 'gmmktime' => ['time', 0],
  66834. ],
  66835. ];
  66836. private array $aliases = [];
  66837. public function getDefinition(): FixerDefinitionInterface
  66838. {
  66839. return new FixerDefinition(
  66840. 'Master functions shall be used instead of aliases.',
  66841. [
  66842. new CodeSample(
  66843. '<?php
  66844. $a = chop($b);
  66845. close($b);
  66846. $a = doubleval($b);
  66847. $a = fputs($b, $c);
  66848. $a = get_required_files();
  66849. ini_alter($b, $c);
  66850. $a = is_double($b);
  66851. $a = is_integer($b);
  66852. $a = is_long($b);
  66853. $a = is_real($b);
  66854. $a = is_writeable($b);
  66855. $a = join($glue, $pieces);
  66856. $a = key_exists($key, $array);
  66857. magic_quotes_runtime($new_setting);
  66858. $a = pos($array);
  66859. $a = show_source($filename, true);
  66860. $a = sizeof($b);
  66861. $a = strchr($haystack, $needle);
  66862. $a = imap_header($imap_stream, 1);
  66863. user_error($message);
  66864. mbereg_search_getregs();
  66865. '
  66866. ),
  66867. new CodeSample(
  66868. '<?php
  66869. $a = is_double($b);
  66870. mbereg_search_getregs();
  66871. ',
  66872. ['sets' => ['@mbreg']]
  66873. ),
  66874. ],
  66875. null,
  66876. 'Risky when any of the alias functions are overridden.'
  66877. );
  66878. }
  66879. public function getPriority(): int
  66880. {
  66881. return 40;
  66882. }
  66883. public function isCandidate(Tokens $tokens): bool
  66884. {
  66885. return $tokens->isTokenKindFound(T_STRING);
  66886. }
  66887. public function isRisky(): bool
  66888. {
  66889. return true;
  66890. }
  66891. protected function configurePostNormalisation(): void
  66892. {
  66893. $this->aliases = [];
  66894. foreach ($this->configuration['sets'] as $set) {
  66895. if ('@all' === $set) {
  66896. $this->aliases = array_merge(...array_values(self::SETS));
  66897. break;
  66898. }
  66899. if (!isset(self::SETS[$set])) {
  66900. throw new \LogicException(\sprintf('Set %s passed option validation, but not part of ::SETS.', $set));
  66901. }
  66902. $this->aliases = array_merge($this->aliases, self::SETS[$set]);
  66903. }
  66904. }
  66905. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66906. {
  66907. $functionsAnalyzer = new FunctionsAnalyzer();
  66908. $argumentsAnalyzer = new ArgumentsAnalyzer();
  66909. foreach ($tokens->findGivenKind(T_STRING) as $index => $token) {
  66910. $tokenContent = strtolower($token->getContent());
  66911. if (!isset($this->aliases[$tokenContent])) {
  66912. continue;
  66913. }
  66914. $openParenthesis = $tokens->getNextMeaningfulToken($index);
  66915. if (!$tokens[$openParenthesis]->equals('(')) {
  66916. continue;
  66917. }
  66918. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  66919. continue;
  66920. }
  66921. if (\is_array($this->aliases[$tokenContent])) {
  66922. [$alias, $numberOfArguments] = $this->aliases[$tokenContent];
  66923. $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis));
  66924. if ($numberOfArguments !== $count) {
  66925. continue;
  66926. }
  66927. } else {
  66928. $alias = $this->aliases[$tokenContent];
  66929. }
  66930. $tokens[$index] = new Token([T_STRING, $alias]);
  66931. }
  66932. }
  66933. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  66934. {
  66935. $sets = [
  66936. '@all' => 'all listed sets',
  66937. '@internal' => 'native functions',
  66938. '@exif' => 'EXIF functions',
  66939. '@ftp' => 'FTP functions',
  66940. '@IMAP' => 'IMAP functions',
  66941. '@ldap' => 'LDAP functions',
  66942. '@mbreg' => 'from `ext-mbstring`',
  66943. '@mysqli' => 'mysqli functions',
  66944. '@oci' => 'oci functions',
  66945. '@odbc' => 'odbc functions',
  66946. '@openssl' => 'openssl functions',
  66947. '@pcntl' => 'PCNTL functions',
  66948. '@pg' => 'pg functions',
  66949. '@posix' => 'POSIX functions',
  66950. '@snmp' => 'SNMP functions',
  66951. '@sodium' => 'libsodium functions',
  66952. '@time' => 'time functions',
  66953. ];
  66954. $list = "List of sets to fix. Defined sets are:\n\n";
  66955. foreach ($sets as $set => $description) {
  66956. $list .= \sprintf("* `%s` (%s);\n", $set, $description);
  66957. }
  66958. $list = rtrim($list, ";\n").'.';
  66959. return new FixerConfigurationResolver([
  66960. (new FixerOptionBuilder('sets', $list))
  66961. ->setAllowedTypes(['string[]'])
  66962. ->setAllowedValues([new AllowedValueSubset(array_keys($sets))])
  66963. ->setDefault(['@internal', '@IMAP', '@pg'])
  66964. ->getOption(),
  66965. ]);
  66966. }
  66967. }
  66968. <?php
  66969. declare(strict_types=1);
  66970. namespace PhpCsFixer\Fixer\Alias;
  66971. use PhpCsFixer\AbstractFixer;
  66972. use PhpCsFixer\FixerDefinition\CodeSample;
  66973. use PhpCsFixer\FixerDefinition\FixerDefinition;
  66974. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  66975. use PhpCsFixer\Tokenizer\Token;
  66976. use PhpCsFixer\Tokenizer\Tokens;
  66977. final class NoAliasLanguageConstructCallFixer extends AbstractFixer
  66978. {
  66979. public function getDefinition(): FixerDefinitionInterface
  66980. {
  66981. return new FixerDefinition(
  66982. 'Master language constructs shall be used instead of aliases.',
  66983. [
  66984. new CodeSample(
  66985. '<?php
  66986. die;
  66987. '
  66988. ),
  66989. ]
  66990. );
  66991. }
  66992. public function isCandidate(Tokens $tokens): bool
  66993. {
  66994. return $tokens->isTokenKindFound(T_EXIT);
  66995. }
  66996. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  66997. {
  66998. foreach ($tokens as $index => $token) {
  66999. if (!$token->isGivenKind(T_EXIT)) {
  67000. continue;
  67001. }
  67002. if ('exit' === strtolower($token->getContent())) {
  67003. continue;
  67004. }
  67005. $tokens[$index] = new Token([T_EXIT, 'exit']);
  67006. }
  67007. }
  67008. }
  67009. <?php
  67010. declare(strict_types=1);
  67011. namespace PhpCsFixer\Fixer\Alias;
  67012. use PhpCsFixer\AbstractFunctionReferenceFixer;
  67013. use PhpCsFixer\FixerDefinition\CodeSample;
  67014. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67015. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67016. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  67017. use PhpCsFixer\Tokenizer\CT;
  67018. use PhpCsFixer\Tokenizer\Token;
  67019. use PhpCsFixer\Tokenizer\Tokens;
  67020. final class PowToExponentiationFixer extends AbstractFunctionReferenceFixer
  67021. {
  67022. public function isCandidate(Tokens $tokens): bool
  67023. {
  67024. return $tokens->count() > 7 && $tokens->isTokenKindFound(T_STRING);
  67025. }
  67026. public function getDefinition(): FixerDefinitionInterface
  67027. {
  67028. return new FixerDefinition(
  67029. 'Converts `pow` to the `**` operator.',
  67030. [
  67031. new CodeSample(
  67032. "<?php\n pow(\$a, 1);\n"
  67033. ),
  67034. ],
  67035. null,
  67036. 'Risky when the function `pow` is overridden.'
  67037. );
  67038. }
  67039. public function getPriority(): int
  67040. {
  67041. return 32;
  67042. }
  67043. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67044. {
  67045. $candidates = $this->findPowCalls($tokens);
  67046. $argumentsAnalyzer = new ArgumentsAnalyzer();
  67047. $numberOfTokensAdded = 0;
  67048. $previousCloseParenthesisIndex = \count($tokens);
  67049. foreach (array_reverse($candidates) as $candidate) {
  67050. if ($previousCloseParenthesisIndex < $candidate[2]) {
  67051. $previousCloseParenthesisIndex = $candidate[2];
  67052. $candidate[2] += $numberOfTokensAdded;
  67053. } else {
  67054. $previousCloseParenthesisIndex = $candidate[2];
  67055. $numberOfTokensAdded = 0;
  67056. }
  67057. $arguments = $argumentsAnalyzer->getArguments($tokens, $candidate[1], $candidate[2]);
  67058. if (2 !== \count($arguments)) {
  67059. continue;
  67060. }
  67061. for ($i = $candidate[1]; $i < $candidate[2]; ++$i) {
  67062. if ($tokens[$i]->isGivenKind(T_ELLIPSIS)) {
  67063. continue 2;
  67064. }
  67065. }
  67066. $numberOfTokensAdded += $this->fixPowToExponentiation(
  67067. $tokens,
  67068. $candidate[0],
  67069. $candidate[1],
  67070. $candidate[2],
  67071. $arguments
  67072. );
  67073. }
  67074. }
  67075. private function findPowCalls(Tokens $tokens): array
  67076. {
  67077. $candidates = [];
  67078. $end = \count($tokens) - 6;
  67079. for ($i = 1; $i < $end; ++$i) {
  67080. $candidate = $this->find('pow', $tokens, $i, $end);
  67081. if (null === $candidate) {
  67082. break;
  67083. }
  67084. $i = $candidate[1];
  67085. $candidates[] = $candidate;
  67086. }
  67087. return $candidates;
  67088. }
  67089. private function fixPowToExponentiation(Tokens $tokens, int $functionNameIndex, int $openParenthesisIndex, int $closeParenthesisIndex, array $arguments): int
  67090. {
  67091. $tokens[$tokens->getNextTokenOfKind(reset($arguments), [','])] = new Token([T_POW, '**']);
  67092. $tokens->clearAt($closeParenthesisIndex);
  67093. $previousIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  67094. if ($tokens[$previousIndex]->equals(',')) {
  67095. $tokens->clearAt($previousIndex);
  67096. }
  67097. $added = 0;
  67098. foreach (array_reverse($arguments, true) as $argumentStartIndex => $argumentEndIndex) {
  67099. if ($this->isParenthesisNeeded($tokens, $argumentStartIndex, $argumentEndIndex)) {
  67100. $tokens->insertAt($argumentEndIndex + 1, new Token(')'));
  67101. $tokens->insertAt($argumentStartIndex, new Token('('));
  67102. $added += 2;
  67103. }
  67104. }
  67105. $tokens->clearAt($openParenthesisIndex);
  67106. $tokens->clearAt($functionNameIndex);
  67107. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($functionNameIndex);
  67108. if ($tokens[$prevMeaningfulTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  67109. $tokens->clearAt($prevMeaningfulTokenIndex);
  67110. }
  67111. return $added;
  67112. }
  67113. private function isParenthesisNeeded(Tokens $tokens, int $argumentStartIndex, int $argumentEndIndex): bool
  67114. {
  67115. static $allowedKinds = null;
  67116. if (null === $allowedKinds) {
  67117. $allowedKinds = $this->getAllowedKinds();
  67118. }
  67119. for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
  67120. if ($tokens[$i]->isGivenKind($allowedKinds) || $tokens->isEmptyAt($i)) {
  67121. continue;
  67122. }
  67123. $blockType = Tokens::detectBlockType($tokens[$i]);
  67124. if (null !== $blockType) {
  67125. $i = $tokens->findBlockEnd($blockType['type'], $i);
  67126. continue;
  67127. }
  67128. if ($tokens[$i]->equals('$')) {
  67129. $i = $tokens->getNextMeaningfulToken($i);
  67130. if ($tokens[$i]->isGivenKind(CT::T_DYNAMIC_VAR_BRACE_OPEN)) {
  67131. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE, $i);
  67132. continue;
  67133. }
  67134. }
  67135. if ($tokens[$i]->equals('+') && $tokens->getPrevMeaningfulToken($i) < $argumentStartIndex) {
  67136. continue;
  67137. }
  67138. return true;
  67139. }
  67140. return false;
  67141. }
  67142. private function getAllowedKinds(): array
  67143. {
  67144. return [
  67145. T_DNUMBER, T_LNUMBER, T_VARIABLE, T_STRING, T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_CAST,
  67146. T_INT_CAST, T_INC, T_DEC, T_NS_SEPARATOR, T_WHITESPACE, T_DOUBLE_COLON, T_LINE, T_COMMENT, T_DOC_COMMENT,
  67147. CT::T_NAMESPACE_OPERATOR,
  67148. ...Token::getObjectOperatorKinds(),
  67149. ];
  67150. }
  67151. }
  67152. <?php
  67153. declare(strict_types=1);
  67154. namespace PhpCsFixer\Fixer\Alias;
  67155. use PhpCsFixer\AbstractFixer;
  67156. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  67157. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  67158. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  67159. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  67160. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  67161. use PhpCsFixer\FixerDefinition\CodeSample;
  67162. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67163. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67164. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  67165. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  67166. use PhpCsFixer\Tokenizer\Token;
  67167. use PhpCsFixer\Tokenizer\Tokens;
  67168. /**
  67169. @phpstan-type
  67170. @phpstan-type
  67171. @implements
  67172. */
  67173. final class ModernizeStrposFixer extends AbstractFixer implements ConfigurableFixerInterface
  67174. {
  67175. /**
  67176. @use */
  67177. use ConfigurableFixerTrait;
  67178. private const REPLACEMENTS = [
  67179. [
  67180. 'operator' => [T_IS_IDENTICAL, '==='],
  67181. 'operand' => [T_LNUMBER, '0'],
  67182. 'replacement' => [T_STRING, 'str_starts_with'],
  67183. 'negate' => false,
  67184. ],
  67185. [
  67186. 'operator' => [T_IS_NOT_IDENTICAL, '!=='],
  67187. 'operand' => [T_LNUMBER, '0'],
  67188. 'replacement' => [T_STRING, 'str_starts_with'],
  67189. 'negate' => true,
  67190. ],
  67191. [
  67192. 'operator' => [T_IS_NOT_IDENTICAL, '!=='],
  67193. 'operand' => [T_STRING, 'false'],
  67194. 'replacement' => [T_STRING, 'str_contains'],
  67195. 'negate' => false,
  67196. ],
  67197. [
  67198. 'operator' => [T_IS_IDENTICAL, '==='],
  67199. 'operand' => [T_STRING, 'false'],
  67200. 'replacement' => [T_STRING, 'str_contains'],
  67201. 'negate' => true,
  67202. ],
  67203. ];
  67204. private bool $modernizeStripos = false;
  67205. public function getDefinition(): FixerDefinitionInterface
  67206. {
  67207. return new FixerDefinition(
  67208. 'Replace `strpos()` and `stripos()` calls with `str_starts_with()` or `str_contains()` if possible.',
  67209. [
  67210. new CodeSample(
  67211. '<?php
  67212. if (strpos($haystack, $needle) === 0) {}
  67213. if (strpos($haystack, $needle) !== 0) {}
  67214. if (strpos($haystack, $needle) !== false) {}
  67215. if (strpos($haystack, $needle) === false) {}
  67216. ',
  67217. ),
  67218. new CodeSample(
  67219. '<?php
  67220. if (strpos($haystack, $needle) === 0) {}
  67221. if (strpos($haystack, $needle) !== 0) {}
  67222. if (strpos($haystack, $needle) !== false) {}
  67223. if (strpos($haystack, $needle) === false) {}
  67224. if (stripos($haystack, $needle) === 0) {}
  67225. if (stripos($haystack, $needle) !== 0) {}
  67226. if (stripos($haystack, $needle) !== false) {}
  67227. if (stripos($haystack, $needle) === false) {}
  67228. ',
  67229. ['modernize_stripos' => true]
  67230. ),
  67231. ],
  67232. null,
  67233. 'Risky if `strpos`, `stripos`, `str_starts_with`, `str_contains` or `strtolower` functions are overridden.'
  67234. );
  67235. }
  67236. public function getPriority(): int
  67237. {
  67238. return 37;
  67239. }
  67240. public function isCandidate(Tokens $tokens): bool
  67241. {
  67242. return $tokens->isTokenKindFound(T_STRING) && $tokens->isAnyTokenKindsFound([T_IS_IDENTICAL, T_IS_NOT_IDENTICAL]);
  67243. }
  67244. public function isRisky(): bool
  67245. {
  67246. return true;
  67247. }
  67248. protected function configurePostNormalisation(): void
  67249. {
  67250. if (isset($this->configuration['modernize_stripos']) && true === $this->configuration['modernize_stripos']) {
  67251. $this->modernizeStripos = true;
  67252. }
  67253. }
  67254. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  67255. {
  67256. return new FixerConfigurationResolver([
  67257. (new FixerOptionBuilder('modernize_stripos', 'Whether to modernize `stripos` calls as well.'))
  67258. ->setAllowedTypes(['bool'])
  67259. ->setDefault(false)
  67260. ->getOption(),
  67261. ]);
  67262. }
  67263. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67264. {
  67265. $functionsAnalyzer = new FunctionsAnalyzer();
  67266. $argumentsAnalyzer = new ArgumentsAnalyzer();
  67267. $modernizeCandidates = [[T_STRING, 'strpos']];
  67268. if ($this->modernizeStripos) {
  67269. $modernizeCandidates[] = [T_STRING, 'stripos'];
  67270. }
  67271. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  67272. if (!$tokens[$index]->equalsAny($modernizeCandidates, false) || !$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  67273. continue;
  67274. }
  67275. $openIndex = $tokens->getNextMeaningfulToken($index);
  67276. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  67277. $arguments = $argumentsAnalyzer->getArguments($tokens, $openIndex, $closeIndex);
  67278. if (2 !== \count($arguments)) {
  67279. continue;
  67280. }
  67281. $compareTokens = $this->getCompareTokens($tokens, $index, -1);
  67282. if (null === $compareTokens) {
  67283. $compareTokens = $this->getCompareTokens($tokens, $closeIndex, 1);
  67284. }
  67285. if (null !== $compareTokens) {
  67286. $isCaseInsensitive = $tokens[$index]->equals([T_STRING, 'stripos'], false);
  67287. $this->fixCall($tokens, $index, $compareTokens, $isCaseInsensitive);
  67288. }
  67289. }
  67290. }
  67291. private function fixCall(Tokens $tokens, int $functionIndex, array $operatorIndices, bool $isCaseInsensitive): void
  67292. {
  67293. foreach (self::REPLACEMENTS as $replacement) {
  67294. if (!$tokens[$operatorIndices['operator_index']]->equals($replacement['operator'])) {
  67295. continue;
  67296. }
  67297. if (!$tokens[$operatorIndices['operand_index']]->equals($replacement['operand'], false)) {
  67298. continue;
  67299. }
  67300. $tokens->clearTokenAndMergeSurroundingWhitespace($operatorIndices['operator_index']);
  67301. $tokens->clearTokenAndMergeSurroundingWhitespace($operatorIndices['operand_index']);
  67302. $tokens->clearTokenAndMergeSurroundingWhitespace($functionIndex);
  67303. if ($replacement['negate']) {
  67304. $negateInsertIndex = $functionIndex;
  67305. $prevFunctionIndex = $tokens->getPrevMeaningfulToken($functionIndex);
  67306. if ($tokens[$prevFunctionIndex]->isGivenKind(T_NS_SEPARATOR)) {
  67307. $negateInsertIndex = $prevFunctionIndex;
  67308. }
  67309. $tokens->insertAt($negateInsertIndex, new Token('!'));
  67310. ++$functionIndex;
  67311. }
  67312. $tokens->insertAt($functionIndex, new Token($replacement['replacement']));
  67313. if ($isCaseInsensitive) {
  67314. $this->wrapArgumentsWithStrToLower($tokens, $functionIndex);
  67315. }
  67316. break;
  67317. }
  67318. }
  67319. private function wrapArgumentsWithStrToLower(Tokens $tokens, int $functionIndex): void
  67320. {
  67321. $argumentsAnalyzer = new ArgumentsAnalyzer();
  67322. $shouldAddNamespace = $tokens[$functionIndex - 1]->isGivenKind(T_NS_SEPARATOR);
  67323. $openIndex = $tokens->getNextMeaningfulToken($functionIndex);
  67324. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  67325. $arguments = $argumentsAnalyzer->getArguments($tokens, $openIndex, $closeIndex);
  67326. $firstArgumentIndexStart = array_key_first($arguments);
  67327. if (!isset($arguments[$firstArgumentIndexStart])) {
  67328. return;
  67329. }
  67330. $firstArgumentIndexEnd = $arguments[$firstArgumentIndexStart] + 3 + ($shouldAddNamespace ? 1 : 0);
  67331. $isSecondArgumentTokenWhiteSpace = $tokens[array_key_last($arguments)]->isGivenKind(T_WHITESPACE);
  67332. if ($isSecondArgumentTokenWhiteSpace) {
  67333. $secondArgumentIndexStart = $tokens->getNextMeaningfulToken(array_key_last($arguments));
  67334. } else {
  67335. $secondArgumentIndexStart = array_key_last($arguments);
  67336. }
  67337. $secondArgumentIndexStart += 3 + ($shouldAddNamespace ? 1 : 0);
  67338. if (!isset($arguments[array_key_last($arguments)])) {
  67339. return;
  67340. }
  67341. $secondArgumentIndexEnd = $arguments[array_key_last($arguments)] + 6 + ($shouldAddNamespace ? 1 : 0) + ($isSecondArgumentTokenWhiteSpace ? 1 : 0);
  67342. if ($shouldAddNamespace) {
  67343. $tokens->insertAt($firstArgumentIndexStart, new Token([T_NS_SEPARATOR, '\\']));
  67344. ++$firstArgumentIndexStart;
  67345. }
  67346. $tokens->insertAt($firstArgumentIndexStart, [new Token([T_STRING, 'strtolower']), new Token('(')]);
  67347. $tokens->insertAt($firstArgumentIndexEnd, new Token(')'));
  67348. if ($shouldAddNamespace) {
  67349. $tokens->insertAt($secondArgumentIndexStart, new Token([T_NS_SEPARATOR, '\\']));
  67350. ++$secondArgumentIndexStart;
  67351. }
  67352. $tokens->insertAt($secondArgumentIndexStart, [new Token([T_STRING, 'strtolower']), new Token('(')]);
  67353. $tokens->insertAt($secondArgumentIndexEnd, new Token(')'));
  67354. }
  67355. private function getCompareTokens(Tokens $tokens, int $offsetIndex, int $direction): ?array
  67356. {
  67357. $operatorIndex = $tokens->getMeaningfulTokenSibling($offsetIndex, $direction);
  67358. if (null !== $operatorIndex && $tokens[$operatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  67359. $operatorIndex = $tokens->getMeaningfulTokenSibling($operatorIndex, $direction);
  67360. }
  67361. if (null === $operatorIndex || !$tokens[$operatorIndex]->isGivenKind([T_IS_IDENTICAL, T_IS_NOT_IDENTICAL])) {
  67362. return null;
  67363. }
  67364. $operandIndex = $tokens->getMeaningfulTokenSibling($operatorIndex, $direction);
  67365. if (null === $operandIndex) {
  67366. return null;
  67367. }
  67368. $operand = $tokens[$operandIndex];
  67369. if (!$operand->equals([T_LNUMBER, '0']) && !$operand->equals([T_STRING, 'false'], false)) {
  67370. return null;
  67371. }
  67372. $precedenceTokenIndex = $tokens->getMeaningfulTokenSibling($operandIndex, $direction);
  67373. if (null !== $precedenceTokenIndex && $this->isOfHigherPrecedence($tokens[$precedenceTokenIndex])) {
  67374. return null;
  67375. }
  67376. return ['operator_index' => $operatorIndex, 'operand_index' => $operandIndex];
  67377. }
  67378. private function isOfHigherPrecedence(Token $token): bool
  67379. {
  67380. static $operatorsKinds = [
  67381. T_DEC,
  67382. T_INC,
  67383. T_INSTANCEOF,
  67384. T_IS_GREATER_OR_EQUAL,
  67385. T_IS_SMALLER_OR_EQUAL,
  67386. T_POW,
  67387. T_SL,
  67388. T_SR,
  67389. ];
  67390. static $operatorsPerContent = [
  67391. '!',
  67392. '%',
  67393. '*',
  67394. '+',
  67395. '-',
  67396. '.',
  67397. '/',
  67398. '<',
  67399. '>',
  67400. '~',
  67401. ];
  67402. return $token->isGivenKind($operatorsKinds) || $token->equalsAny($operatorsPerContent);
  67403. }
  67404. }
  67405. <?php
  67406. declare(strict_types=1);
  67407. namespace PhpCsFixer\Fixer\Alias;
  67408. use PhpCsFixer\AbstractFixer;
  67409. use PhpCsFixer\FixerDefinition\CodeSample;
  67410. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67411. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67412. use PhpCsFixer\Preg;
  67413. use PhpCsFixer\PregException;
  67414. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  67415. use PhpCsFixer\Tokenizer\Token;
  67416. use PhpCsFixer\Tokenizer\Tokens;
  67417. final class EregToPregFixer extends AbstractFixer
  67418. {
  67419. private const FUNCTIONS = [
  67420. ['ereg', 'preg_match', ''],
  67421. ['eregi', 'preg_match', 'i'],
  67422. ['ereg_replace', 'preg_replace', ''],
  67423. ['eregi_replace', 'preg_replace', 'i'],
  67424. ['split', 'preg_split', ''],
  67425. ['spliti', 'preg_split', 'i'],
  67426. ];
  67427. private static array $delimiters = ['/', '#', '!'];
  67428. public function getDefinition(): FixerDefinitionInterface
  67429. {
  67430. return new FixerDefinition(
  67431. 'Replace deprecated `ereg` regular expression functions with `preg`.',
  67432. [new CodeSample("<?php \$x = ereg('[A-Z]');\n")],
  67433. null,
  67434. 'Risky if the `ereg` function is overridden.'
  67435. );
  67436. }
  67437. public function getPriority(): int
  67438. {
  67439. return 0;
  67440. }
  67441. public function isCandidate(Tokens $tokens): bool
  67442. {
  67443. return $tokens->isTokenKindFound(T_STRING);
  67444. }
  67445. public function isRisky(): bool
  67446. {
  67447. return true;
  67448. }
  67449. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67450. {
  67451. $end = $tokens->count() - 1;
  67452. $functionsAnalyzer = new FunctionsAnalyzer();
  67453. foreach (self::FUNCTIONS as $map) {
  67454. $seq = [[T_STRING, $map[0]], '(', [T_CONSTANT_ENCAPSED_STRING]];
  67455. $currIndex = 0;
  67456. while (true) {
  67457. $match = $tokens->findSequence($seq, $currIndex, $end, false);
  67458. if (null === $match) {
  67459. break;
  67460. }
  67461. $match = array_keys($match);
  67462. $currIndex = $match[2];
  67463. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $match[0])) {
  67464. continue;
  67465. }
  67466. $next = $tokens->getNextMeaningfulToken($match[2]);
  67467. if (null === $next || !$tokens[$next]->equalsAny([',', ')'])) {
  67468. continue;
  67469. }
  67470. $regexTokenContent = $tokens[$match[2]]->getContent();
  67471. if ('b' === $regexTokenContent[0] || 'B' === $regexTokenContent[0]) {
  67472. $quote = $regexTokenContent[1];
  67473. $prefix = $regexTokenContent[0];
  67474. $string = substr($regexTokenContent, 2, -1);
  67475. } else {
  67476. $quote = $regexTokenContent[0];
  67477. $prefix = '';
  67478. $string = substr($regexTokenContent, 1, -1);
  67479. }
  67480. $delim = $this->getBestDelimiter($string);
  67481. $preg = $delim.addcslashes($string, $delim).$delim.'D'.$map[2];
  67482. if (!$this->checkPreg($preg)) {
  67483. continue;
  67484. }
  67485. $tokens[$match[0]] = new Token([T_STRING, $map[1]]);
  67486. $tokens[$match[2]] = new Token([T_CONSTANT_ENCAPSED_STRING, $prefix.$quote.$preg.$quote]);
  67487. }
  67488. }
  67489. }
  67490. private function checkPreg(string $pattern): bool
  67491. {
  67492. try {
  67493. Preg::match($pattern, '');
  67494. return true;
  67495. } catch (PregException $e) {
  67496. return false;
  67497. }
  67498. }
  67499. private function getBestDelimiter(string $pattern): string
  67500. {
  67501. $delimiters = [];
  67502. foreach (self::$delimiters as $k => $d) {
  67503. if (!str_contains($pattern, $d)) {
  67504. return $d;
  67505. }
  67506. $delimiters[$d] = [substr_count($pattern, $d), $k];
  67507. }
  67508. uasort($delimiters, static function (array $a, array $b): int {
  67509. if ($a[0] === $b[0]) {
  67510. return $a[1] <=> $b[1];
  67511. }
  67512. return $a[0] <=> $b[0];
  67513. });
  67514. return array_key_first($delimiters);
  67515. }
  67516. }
  67517. <?php
  67518. declare(strict_types=1);
  67519. namespace PhpCsFixer\Fixer;
  67520. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  67521. use PhpCsFixer\ConfigurationException\InvalidForEnvFixerConfigurationException;
  67522. use PhpCsFixer\ConfigurationException\RequiredFixerConfigurationException;
  67523. use PhpCsFixer\Console\Application;
  67524. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  67525. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  67526. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  67527. use PhpCsFixer\Utils;
  67528. use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
  67529. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  67530. /**
  67531. @template
  67532. @template
  67533. */
  67534. trait ConfigurableFixerTrait
  67535. {
  67536. protected ?array $configuration = null;
  67537. private ?FixerConfigurationResolverInterface $configurationDefinition = null;
  67538. final public function configure(array $configuration): void
  67539. {
  67540. $this->configurePreNormalisation($configuration);
  67541. foreach ($this->getConfigurationDefinition()->getOptions() as $option) {
  67542. if (!$option instanceof DeprecatedFixerOption) {
  67543. continue;
  67544. }
  67545. $name = $option->getName();
  67546. if (\array_key_exists($name, $configuration)) {
  67547. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  67548. 'Option "%s" for rule "%s" is deprecated and will be removed in version %d.0. %s',
  67549. $name,
  67550. $this->getName(),
  67551. Application::getMajorVersion() + 1,
  67552. str_replace('`', '"', $option->getDeprecationMessage())
  67553. )));
  67554. }
  67555. }
  67556. try {
  67557. $this->configuration = $this->getConfigurationDefinition()->resolve($configuration);
  67558. } catch (MissingOptionsException $exception) {
  67559. throw new RequiredFixerConfigurationException(
  67560. $this->getName(),
  67561. \sprintf('Missing required configuration: %s', $exception->getMessage()),
  67562. $exception
  67563. );
  67564. } catch (InvalidOptionsForEnvException $exception) {
  67565. throw new InvalidForEnvFixerConfigurationException(
  67566. $this->getName(),
  67567. \sprintf('Invalid configuration for env: %s', $exception->getMessage()),
  67568. $exception
  67569. );
  67570. } catch (ExceptionInterface $exception) {
  67571. throw new InvalidFixerConfigurationException(
  67572. $this->getName(),
  67573. \sprintf('Invalid configuration: %s', $exception->getMessage()),
  67574. $exception
  67575. );
  67576. }
  67577. $this->configurePostNormalisation();
  67578. }
  67579. final public function getConfigurationDefinition(): FixerConfigurationResolverInterface
  67580. {
  67581. if (null === $this->configurationDefinition) {
  67582. $this->configurationDefinition = $this->createConfigurationDefinition();
  67583. }
  67584. return $this->configurationDefinition;
  67585. }
  67586. abstract public function getName(): string;
  67587. protected function configurePreNormalisation(array &$configuration): void
  67588. {
  67589. }
  67590. protected function configurePostNormalisation(): void
  67591. {
  67592. }
  67593. abstract protected function createConfigurationDefinition(): FixerConfigurationResolverInterface;
  67594. }
  67595. <?php
  67596. declare(strict_types=1);
  67597. namespace PhpCsFixer\Fixer;
  67598. interface InternalFixerInterface extends FixerInterface {}
  67599. <?php
  67600. declare(strict_types=1);
  67601. namespace PhpCsFixer\Fixer;
  67602. use PhpCsFixer\Preg;
  67603. use PhpCsFixer\Tokenizer\Tokens;
  67604. trait Indentation
  67605. {
  67606. private function getLineIndentation(Tokens $tokens, int $index): string
  67607. {
  67608. $newlineTokenIndex = $this->getPreviousNewlineTokenIndex($tokens, $index);
  67609. if (null === $newlineTokenIndex) {
  67610. return '';
  67611. }
  67612. return $this->extractIndent($this->computeNewLineContent($tokens, $newlineTokenIndex));
  67613. }
  67614. private function extractIndent(string $content): string
  67615. {
  67616. if (Preg::match('/\R(\h*)[^\r\n]*$/D', $content, $matches)) {
  67617. return $matches[1];
  67618. }
  67619. return '';
  67620. }
  67621. private function getPreviousNewlineTokenIndex(Tokens $tokens, int $index): ?int
  67622. {
  67623. while ($index > 0) {
  67624. $index = $tokens->getPrevTokenOfKind($index, [[T_WHITESPACE], [T_INLINE_HTML]]);
  67625. if (null === $index) {
  67626. break;
  67627. }
  67628. if ($this->isNewLineToken($tokens, $index)) {
  67629. return $index;
  67630. }
  67631. }
  67632. return null;
  67633. }
  67634. private function computeNewLineContent(Tokens $tokens, int $index): string
  67635. {
  67636. $content = $tokens[$index]->getContent();
  67637. if (0 !== $index && $tokens[$index - 1]->equalsAny([[T_OPEN_TAG], [T_CLOSE_TAG]])) {
  67638. $content = Preg::replace('/\S/', '', $tokens[$index - 1]->getContent()).$content;
  67639. }
  67640. return $content;
  67641. }
  67642. private function isNewLineToken(Tokens $tokens, int $index): bool
  67643. {
  67644. $token = $tokens[$index];
  67645. if (
  67646. $token->isGivenKind(T_OPEN_TAG)
  67647. && isset($tokens[$index + 1])
  67648. && !$tokens[$index + 1]->isWhitespace()
  67649. && Preg::match('/\R/', $token->getContent())
  67650. ) {
  67651. return true;
  67652. }
  67653. if (!$tokens[$index]->isGivenKind([T_WHITESPACE, T_INLINE_HTML])) {
  67654. return false;
  67655. }
  67656. return Preg::match('/\R/', $this->computeNewLineContent($tokens, $index));
  67657. }
  67658. }
  67659. <?php
  67660. declare(strict_types=1);
  67661. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67662. use PhpCsFixer\AbstractFixer;
  67663. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  67664. use PhpCsFixer\FixerDefinition\CodeSample;
  67665. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67666. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67667. use PhpCsFixer\Preg;
  67668. use PhpCsFixer\Tokenizer\Token;
  67669. use PhpCsFixer\Tokenizer\Tokens;
  67670. final class BlankLineAfterNamespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  67671. {
  67672. public function getDefinition(): FixerDefinitionInterface
  67673. {
  67674. return new FixerDefinition(
  67675. 'There MUST be one blank line after the namespace declaration.',
  67676. [
  67677. new CodeSample("<?php\nnamespace Sample\\Sample;\n\n\n\$a;\n"),
  67678. new CodeSample("<?php\nnamespace Sample\\Sample;\nClass Test{}\n"),
  67679. ]
  67680. );
  67681. }
  67682. public function getPriority(): int
  67683. {
  67684. return -20;
  67685. }
  67686. public function isCandidate(Tokens $tokens): bool
  67687. {
  67688. return $tokens->isTokenKindFound(T_NAMESPACE);
  67689. }
  67690. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67691. {
  67692. $lastIndex = $tokens->count() - 1;
  67693. for ($index = $lastIndex; $index >= 0; --$index) {
  67694. $token = $tokens[$index];
  67695. if (!$token->isGivenKind(T_NAMESPACE)) {
  67696. continue;
  67697. }
  67698. $semicolonIndex = $tokens->getNextTokenOfKind($index, [';', '{', [T_CLOSE_TAG]]);
  67699. $semicolonToken = $tokens[$semicolonIndex];
  67700. if (!$semicolonToken->equals(';')) {
  67701. continue;
  67702. }
  67703. $indexToEnsureBlankLineAfter = $this->getIndexToEnsureBlankLineAfter($tokens, $semicolonIndex);
  67704. $indexToEnsureBlankLine = $tokens->getNonEmptySibling($indexToEnsureBlankLineAfter, 1);
  67705. if (null !== $indexToEnsureBlankLine && $tokens[$indexToEnsureBlankLine]->isWhitespace()) {
  67706. $tokens[$indexToEnsureBlankLine] = $this->getTokenToInsert($tokens[$indexToEnsureBlankLine]->getContent(), $indexToEnsureBlankLine === $lastIndex);
  67707. } else {
  67708. $tokens->insertAt($indexToEnsureBlankLineAfter + 1, $this->getTokenToInsert('', $indexToEnsureBlankLineAfter === $lastIndex));
  67709. }
  67710. }
  67711. }
  67712. private function getIndexToEnsureBlankLineAfter(Tokens $tokens, int $index): int
  67713. {
  67714. $indexToEnsureBlankLine = $index;
  67715. $nextIndex = $tokens->getNonEmptySibling($indexToEnsureBlankLine, 1);
  67716. while (null !== $nextIndex) {
  67717. $token = $tokens[$nextIndex];
  67718. if ($token->isWhitespace()) {
  67719. if (Preg::match('/\R/', $token->getContent())) {
  67720. break;
  67721. }
  67722. $nextNextIndex = $tokens->getNonEmptySibling($nextIndex, 1);
  67723. if (!$tokens[$nextNextIndex]->isComment()) {
  67724. break;
  67725. }
  67726. }
  67727. if (!$token->isWhitespace() && !$token->isComment()) {
  67728. break;
  67729. }
  67730. $indexToEnsureBlankLine = $nextIndex;
  67731. $nextIndex = $tokens->getNonEmptySibling($indexToEnsureBlankLine, 1);
  67732. }
  67733. return $indexToEnsureBlankLine;
  67734. }
  67735. private function getTokenToInsert(string $currentContent, bool $isLastIndex): Token
  67736. {
  67737. $ending = $this->whitespacesConfig->getLineEnding();
  67738. $emptyLines = $isLastIndex ? $ending : $ending.$ending;
  67739. $indent = Preg::match('/^.*\R( *)$/s', $currentContent, $matches) ? $matches[1] : '';
  67740. return new Token([T_WHITESPACE, $emptyLines.$indent]);
  67741. }
  67742. }
  67743. <?php
  67744. declare(strict_types=1);
  67745. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67746. use PhpCsFixer\AbstractFixer;
  67747. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  67748. use PhpCsFixer\FixerDefinition\CodeSample;
  67749. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67750. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67751. use PhpCsFixer\Tokenizer\Token;
  67752. use PhpCsFixer\Tokenizer\Tokens;
  67753. final class NoLeadingNamespaceWhitespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  67754. {
  67755. public function isCandidate(Tokens $tokens): bool
  67756. {
  67757. return $tokens->isTokenKindFound(T_NAMESPACE);
  67758. }
  67759. public function getDefinition(): FixerDefinitionInterface
  67760. {
  67761. return new FixerDefinition(
  67762. 'The namespace declaration line shouldn\'t contain leading whitespace.',
  67763. [
  67764. new CodeSample(
  67765. '<?php
  67766. namespace Test8a;
  67767. namespace Test8b;
  67768. '
  67769. ),
  67770. ]
  67771. );
  67772. }
  67773. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67774. {
  67775. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  67776. $token = $tokens[$index];
  67777. if (!$token->isGivenKind(T_NAMESPACE)) {
  67778. continue;
  67779. }
  67780. $beforeNamespaceIndex = $index - 1;
  67781. $beforeNamespace = $tokens[$beforeNamespaceIndex];
  67782. if (!$beforeNamespace->isWhitespace()) {
  67783. if (!self::endsWithWhitespace($beforeNamespace->getContent())) {
  67784. $tokens->insertAt($index, new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding()]));
  67785. }
  67786. continue;
  67787. }
  67788. $lastNewline = strrpos($beforeNamespace->getContent(), "\n");
  67789. if (false === $lastNewline) {
  67790. $beforeBeforeNamespace = $tokens[$index - 2];
  67791. if (self::endsWithWhitespace($beforeBeforeNamespace->getContent())) {
  67792. $tokens->clearAt($beforeNamespaceIndex);
  67793. } else {
  67794. $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, ' ']);
  67795. }
  67796. } else {
  67797. $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, substr($beforeNamespace->getContent(), 0, $lastNewline + 1)]);
  67798. }
  67799. }
  67800. }
  67801. private static function endsWithWhitespace(string $str): bool
  67802. {
  67803. if ('' === $str) {
  67804. return false;
  67805. }
  67806. return '' === trim(substr($str, -1));
  67807. }
  67808. }
  67809. <?php
  67810. declare(strict_types=1);
  67811. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67812. use PhpCsFixer\AbstractProxyFixer;
  67813. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  67814. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  67815. use PhpCsFixer\FixerDefinition\CodeSample;
  67816. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67817. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67818. use PhpCsFixer\Tokenizer\Tokens;
  67819. final class SingleBlankLineBeforeNamespaceFixer extends AbstractProxyFixer implements WhitespacesAwareFixerInterface, DeprecatedFixerInterface
  67820. {
  67821. public function getSuccessorsNames(): array
  67822. {
  67823. return array_keys($this->proxyFixers);
  67824. }
  67825. public function getDefinition(): FixerDefinitionInterface
  67826. {
  67827. return new FixerDefinition(
  67828. 'There should be exactly one blank line before a namespace declaration.',
  67829. [
  67830. new CodeSample("<?php namespace A {}\n"),
  67831. new CodeSample("<?php\n\n\nnamespace A{}\n"),
  67832. ]
  67833. );
  67834. }
  67835. public function isCandidate(Tokens $tokens): bool
  67836. {
  67837. return $tokens->isTokenKindFound(T_NAMESPACE);
  67838. }
  67839. public function getPriority(): int
  67840. {
  67841. return parent::getPriority();
  67842. }
  67843. protected function createProxyFixers(): array
  67844. {
  67845. $blankLineBeforeNamespace = new BlankLinesBeforeNamespaceFixer();
  67846. $blankLineBeforeNamespace->configure([
  67847. 'min_line_breaks' => 2,
  67848. 'max_line_breaks' => 2,
  67849. ]);
  67850. return [
  67851. $blankLineBeforeNamespace,
  67852. ];
  67853. }
  67854. }
  67855. <?php
  67856. declare(strict_types=1);
  67857. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67858. use PhpCsFixer\AbstractProxyFixer;
  67859. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  67860. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  67861. use PhpCsFixer\FixerDefinition\CodeSample;
  67862. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67863. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67864. use PhpCsFixer\Tokenizer\Tokens;
  67865. final class NoBlankLinesBeforeNamespaceFixer extends AbstractProxyFixer implements WhitespacesAwareFixerInterface, DeprecatedFixerInterface
  67866. {
  67867. public function getSuccessorsNames(): array
  67868. {
  67869. return array_keys($this->proxyFixers);
  67870. }
  67871. public function isCandidate(Tokens $tokens): bool
  67872. {
  67873. return $tokens->isTokenKindFound(T_NAMESPACE);
  67874. }
  67875. public function getDefinition(): FixerDefinitionInterface
  67876. {
  67877. return new FixerDefinition(
  67878. 'There should be no blank lines before a namespace declaration.',
  67879. [
  67880. new CodeSample(
  67881. "<?php\n\n\n\nnamespace Example;\n"
  67882. ),
  67883. ]
  67884. );
  67885. }
  67886. public function getPriority(): int
  67887. {
  67888. return 0;
  67889. }
  67890. protected function createProxyFixers(): array
  67891. {
  67892. $blankLineBeforeNamespace = new BlankLinesBeforeNamespaceFixer();
  67893. $blankLineBeforeNamespace->configure([
  67894. 'min_line_breaks' => 0,
  67895. 'max_line_breaks' => 1,
  67896. ]);
  67897. return [
  67898. $blankLineBeforeNamespace,
  67899. ];
  67900. }
  67901. }
  67902. <?php
  67903. declare(strict_types=1);
  67904. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67905. use PhpCsFixer\AbstractFixer;
  67906. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67907. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67908. use PhpCsFixer\FixerDefinition\VersionSpecification;
  67909. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  67910. use PhpCsFixer\Tokenizer\Tokens;
  67911. final class CleanNamespaceFixer extends AbstractFixer
  67912. {
  67913. public function getDefinition(): FixerDefinitionInterface
  67914. {
  67915. $samples = [];
  67916. foreach (['namespace Foo \ Bar;', 'echo foo /* comment */ \ bar();'] as $sample) {
  67917. $samples[] = new VersionSpecificCodeSample(
  67918. "<?php\n".$sample."\n",
  67919. new VersionSpecification(null, 8_00_00 - 1)
  67920. );
  67921. }
  67922. return new FixerDefinition(
  67923. 'Namespace must not contain spacing, comments or PHPDoc.',
  67924. $samples
  67925. );
  67926. }
  67927. public function isCandidate(Tokens $tokens): bool
  67928. {
  67929. return \PHP_VERSION_ID < 8_00_00 && $tokens->isTokenKindFound(T_NS_SEPARATOR);
  67930. }
  67931. public function getPriority(): int
  67932. {
  67933. return 10;
  67934. }
  67935. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  67936. {
  67937. $count = $tokens->count();
  67938. for ($index = 0; $index < $count; ++$index) {
  67939. if ($tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
  67940. $previousIndex = $tokens->getPrevMeaningfulToken($index);
  67941. $index = $this->fixNamespace(
  67942. $tokens,
  67943. $tokens[$previousIndex]->isGivenKind(T_STRING) ? $previousIndex : $index
  67944. );
  67945. }
  67946. }
  67947. }
  67948. private function fixNamespace(Tokens $tokens, int $index): int
  67949. {
  67950. $tillIndex = $index;
  67951. while ($tokens[$tillIndex]->isGivenKind([T_NS_SEPARATOR, T_STRING])) {
  67952. $tillIndex = $tokens->getNextMeaningfulToken($tillIndex);
  67953. }
  67954. $tillIndex = $tokens->getPrevMeaningfulToken($tillIndex);
  67955. $spaceIndices = [];
  67956. for (; $index <= $tillIndex; ++$index) {
  67957. if ($tokens[$index]->isGivenKind(T_WHITESPACE)) {
  67958. $spaceIndices[] = $index;
  67959. } elseif ($tokens[$index]->isComment()) {
  67960. $tokens->clearAt($index);
  67961. }
  67962. }
  67963. if ($tokens[$index - 1]->isWhitespace()) {
  67964. array_pop($spaceIndices);
  67965. }
  67966. foreach ($spaceIndices as $i) {
  67967. $tokens->clearAt($i);
  67968. }
  67969. return $index;
  67970. }
  67971. }
  67972. <?php
  67973. declare(strict_types=1);
  67974. namespace PhpCsFixer\Fixer\NamespaceNotation;
  67975. use PhpCsFixer\AbstractFixer;
  67976. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  67977. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  67978. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  67979. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  67980. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  67981. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  67982. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  67983. use PhpCsFixer\FixerDefinition\CodeSample;
  67984. use PhpCsFixer\FixerDefinition\FixerDefinition;
  67985. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  67986. use PhpCsFixer\Tokenizer\Token;
  67987. use PhpCsFixer\Tokenizer\Tokens;
  67988. use Symfony\Component\OptionsResolver\Options;
  67989. /**
  67990. @phpstan-type
  67991. @phpstan-type
  67992. @implements
  67993. */
  67994. final class BlankLinesBeforeNamespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface, ConfigurableFixerInterface
  67995. {
  67996. /**
  67997. @use */
  67998. use ConfigurableFixerTrait;
  67999. public function getDefinition(): FixerDefinitionInterface
  68000. {
  68001. return new FixerDefinition(
  68002. 'Controls blank lines before a namespace declaration.',
  68003. [
  68004. new CodeSample("<?php namespace A {}\n"),
  68005. new CodeSample("<?php namespace A {}\n", ['min_line_breaks' => 1]),
  68006. new CodeSample("<?php\n\ndeclare(strict_types=1);\n\n\n\nnamespace A{}\n", ['max_line_breaks' => 2]),
  68007. new CodeSample("<?php\n\n/** Some comment */\nnamespace A{}\n", ['min_line_breaks' => 2]),
  68008. new CodeSample("<?php\n\nnamespace A{}\n", ['min_line_breaks' => 0, 'max_line_breaks' => 0]),
  68009. ]
  68010. );
  68011. }
  68012. public function isCandidate(Tokens $tokens): bool
  68013. {
  68014. return $tokens->isTokenKindFound(T_NAMESPACE);
  68015. }
  68016. public function getPriority(): int
  68017. {
  68018. return -31;
  68019. }
  68020. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  68021. {
  68022. return new FixerConfigurationResolver([
  68023. (new FixerOptionBuilder('min_line_breaks', 'Minimum line breaks that should exist before namespace declaration.'))
  68024. ->setAllowedTypes(['int'])
  68025. ->setDefault(2)
  68026. ->setNormalizer(static function (Options $options, int $value): int {
  68027. if ($value < 0) {
  68028. throw new InvalidFixerConfigurationException(
  68029. (new self())->getName(),
  68030. 'Option `min_line_breaks` cannot be lower than 0.'
  68031. );
  68032. }
  68033. return $value;
  68034. })
  68035. ->getOption(),
  68036. (new FixerOptionBuilder('max_line_breaks', 'Maximum line breaks that should exist before namespace declaration.'))
  68037. ->setAllowedTypes(['int'])
  68038. ->setDefault(2)
  68039. ->setNormalizer(static function (Options $options, int $value): int {
  68040. if ($value < 0) {
  68041. throw new InvalidFixerConfigurationException(
  68042. (new self())->getName(),
  68043. 'Option `max_line_breaks` cannot be lower than 0.'
  68044. );
  68045. }
  68046. if ($value < $options['min_line_breaks']) {
  68047. throw new InvalidFixerConfigurationException(
  68048. (new self())->getName(),
  68049. 'Option `max_line_breaks` cannot have lower value than `min_line_breaks`.'
  68050. );
  68051. }
  68052. return $value;
  68053. })
  68054. ->getOption(),
  68055. ]);
  68056. }
  68057. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68058. {
  68059. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  68060. $token = $tokens[$index];
  68061. if ($token->isGivenKind(T_NAMESPACE)) {
  68062. $this->fixLinesBeforeNamespace(
  68063. $tokens,
  68064. $index,
  68065. $this->configuration['min_line_breaks'],
  68066. $this->configuration['max_line_breaks']
  68067. );
  68068. }
  68069. }
  68070. }
  68071. protected function fixLinesBeforeNamespace(Tokens $tokens, int $index, int $expectedMin, int $expectedMax): void
  68072. {
  68073. $openingTokenIndex = null;
  68074. $precedingNewlines = 0;
  68075. $newlineInOpening = false;
  68076. $openingToken = null;
  68077. for ($i = 1; $i <= 2; ++$i) {
  68078. if (isset($tokens[$index - $i])) {
  68079. $token = $tokens[$index - $i];
  68080. if ($token->isGivenKind(T_OPEN_TAG)) {
  68081. $openingToken = $token;
  68082. $openingTokenIndex = $index - $i;
  68083. $newlineInOpening = str_contains($token->getContent(), "\n");
  68084. if ($newlineInOpening) {
  68085. ++$precedingNewlines;
  68086. }
  68087. break;
  68088. }
  68089. if (false === $token->isGivenKind(T_WHITESPACE)) {
  68090. break;
  68091. }
  68092. $precedingNewlines += substr_count($token->getContent(), "\n");
  68093. }
  68094. }
  68095. if ($precedingNewlines >= $expectedMin && $precedingNewlines <= $expectedMax) {
  68096. return;
  68097. }
  68098. $previousIndex = $index - 1;
  68099. $previous = $tokens[$previousIndex];
  68100. if (0 === $expectedMax) {
  68101. if ($previous->isWhitespace()) {
  68102. $tokens->clearAt($previousIndex);
  68103. }
  68104. if ($newlineInOpening) {
  68105. $tokens[$openingTokenIndex] = new Token([T_OPEN_TAG, rtrim($openingToken->getContent()).' ']);
  68106. }
  68107. return;
  68108. }
  68109. $lineEnding = $this->whitespacesConfig->getLineEnding();
  68110. $newlinesForWhitespaceToken = $precedingNewlines >= $expectedMax
  68111. ? $expectedMax
  68112. : max($precedingNewlines, $expectedMin);
  68113. if (null !== $openingToken) {
  68114. $content = rtrim($openingToken->getContent());
  68115. $newContent = $content.$lineEnding;
  68116. $tokens[$openingTokenIndex] = new Token([T_OPEN_TAG, $newContent]);
  68117. --$newlinesForWhitespaceToken;
  68118. }
  68119. if (0 === $newlinesForWhitespaceToken) {
  68120. if ($previous->isWhitespace()) {
  68121. $tokens->clearAt($previousIndex);
  68122. }
  68123. return;
  68124. }
  68125. if ($previous->isWhitespace()) {
  68126. $tokens[$previousIndex] = new Token(
  68127. [
  68128. T_WHITESPACE,
  68129. str_repeat($lineEnding, $newlinesForWhitespaceToken).substr(
  68130. $previous->getContent(),
  68131. strrpos($previous->getContent(), "\n") + 1
  68132. ),
  68133. ]
  68134. );
  68135. } else {
  68136. $tokens->insertAt($index, new Token([T_WHITESPACE, str_repeat($lineEnding, $newlinesForWhitespaceToken)]));
  68137. }
  68138. }
  68139. }
  68140. <?php
  68141. declare(strict_types=1);
  68142. namespace PhpCsFixer\Fixer\CastNotation;
  68143. use PhpCsFixer\AbstractFixer;
  68144. use PhpCsFixer\FixerDefinition\CodeSample;
  68145. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68146. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68147. use PhpCsFixer\Tokenizer\Token;
  68148. use PhpCsFixer\Tokenizer\Tokens;
  68149. final class NoUnsetCastFixer extends AbstractFixer
  68150. {
  68151. public function getDefinition(): FixerDefinitionInterface
  68152. {
  68153. return new FixerDefinition(
  68154. 'Variables must be set `null` instead of using `(unset)` casting.',
  68155. [new CodeSample("<?php\n\$a = (unset) \$b;\n")]
  68156. );
  68157. }
  68158. public function isCandidate(Tokens $tokens): bool
  68159. {
  68160. return $tokens->isTokenKindFound(T_UNSET_CAST);
  68161. }
  68162. public function getPriority(): int
  68163. {
  68164. return 0;
  68165. }
  68166. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68167. {
  68168. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  68169. if ($tokens[$index]->isGivenKind(T_UNSET_CAST)) {
  68170. $this->fixUnsetCast($tokens, $index);
  68171. }
  68172. }
  68173. }
  68174. private function fixUnsetCast(Tokens $tokens, int $index): void
  68175. {
  68176. $assignmentIndex = $tokens->getPrevMeaningfulToken($index);
  68177. if (null === $assignmentIndex || !$tokens[$assignmentIndex]->equals('=')) {
  68178. return;
  68179. }
  68180. $varIndex = $tokens->getNextMeaningfulToken($index);
  68181. if (null === $varIndex || !$tokens[$varIndex]->isGivenKind(T_VARIABLE)) {
  68182. return;
  68183. }
  68184. $afterVar = $tokens->getNextMeaningfulToken($varIndex);
  68185. if (null === $afterVar || !$tokens[$afterVar]->equalsAny([';', [T_CLOSE_TAG]])) {
  68186. return;
  68187. }
  68188. $nextIsWhiteSpace = $tokens[$assignmentIndex + 1]->isWhitespace();
  68189. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  68190. $tokens->clearTokenAndMergeSurroundingWhitespace($varIndex);
  68191. ++$assignmentIndex;
  68192. if (!$nextIsWhiteSpace) {
  68193. $tokens->insertAt($assignmentIndex, new Token([T_WHITESPACE, ' ']));
  68194. }
  68195. ++$assignmentIndex;
  68196. $tokens->insertAt($assignmentIndex, new Token([T_STRING, 'null']));
  68197. }
  68198. }
  68199. <?php
  68200. declare(strict_types=1);
  68201. namespace PhpCsFixer\Fixer\CastNotation;
  68202. use PhpCsFixer\AbstractFixer;
  68203. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  68204. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  68205. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  68206. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  68207. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  68208. use PhpCsFixer\FixerDefinition\CodeSample;
  68209. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68210. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68211. use PhpCsFixer\Tokenizer\Token;
  68212. use PhpCsFixer\Tokenizer\Tokens;
  68213. /**
  68214. @phpstan-type
  68215. @phpstan-type
  68216. @implements
  68217. */
  68218. final class CastSpacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  68219. {
  68220. /**
  68221. @use */
  68222. use ConfigurableFixerTrait;
  68223. private const INSIDE_CAST_SPACE_REPLACE_MAP = [
  68224. ' ' => '',
  68225. "\t" => '',
  68226. "\n" => '',
  68227. "\r" => '',
  68228. "\0" => '',
  68229. "\x0B" => '',
  68230. ];
  68231. public function getDefinition(): FixerDefinitionInterface
  68232. {
  68233. return new FixerDefinition(
  68234. 'A single space or none should be between cast and variable.',
  68235. [
  68236. new CodeSample(
  68237. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int)\$b;\n"
  68238. ),
  68239. new CodeSample(
  68240. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int)\$b;\n",
  68241. ['space' => 'single']
  68242. ),
  68243. new CodeSample(
  68244. "<?php\n\$bar = ( string ) \$a;\n\$foo = (int) \$b;\n",
  68245. ['space' => 'none']
  68246. ),
  68247. ]
  68248. );
  68249. }
  68250. public function getPriority(): int
  68251. {
  68252. return -10;
  68253. }
  68254. public function isCandidate(Tokens $tokens): bool
  68255. {
  68256. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  68257. }
  68258. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68259. {
  68260. foreach ($tokens as $index => $token) {
  68261. if (!$token->isCast()) {
  68262. continue;
  68263. }
  68264. $tokens[$index] = new Token([
  68265. $token->getId(),
  68266. strtr($token->getContent(), self::INSIDE_CAST_SPACE_REPLACE_MAP),
  68267. ]);
  68268. if ('single' === $this->configuration['space']) {
  68269. if ($tokens[$index + 1]->isWhitespace(" \t")) {
  68270. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  68271. } elseif (!$tokens[$index + 1]->isWhitespace()) {
  68272. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  68273. }
  68274. continue;
  68275. }
  68276. if ($tokens[$index + 1]->isWhitespace()) {
  68277. $tokens->clearAt($index + 1);
  68278. }
  68279. }
  68280. }
  68281. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  68282. {
  68283. return new FixerConfigurationResolver([
  68284. (new FixerOptionBuilder('space', 'Spacing to apply between cast and variable.'))
  68285. ->setAllowedValues(['none', 'single'])
  68286. ->setDefault('single')
  68287. ->getOption(),
  68288. ]);
  68289. }
  68290. }
  68291. <?php
  68292. declare(strict_types=1);
  68293. namespace PhpCsFixer\Fixer\CastNotation;
  68294. use PhpCsFixer\AbstractFixer;
  68295. use PhpCsFixer\FixerDefinition\CodeSample;
  68296. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68297. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68298. use PhpCsFixer\Tokenizer\Token;
  68299. use PhpCsFixer\Tokenizer\Tokens;
  68300. final class NoShortBoolCastFixer extends AbstractFixer
  68301. {
  68302. public function getPriority(): int
  68303. {
  68304. return -9;
  68305. }
  68306. public function getDefinition(): FixerDefinitionInterface
  68307. {
  68308. return new FixerDefinition(
  68309. 'Short cast `bool` using double exclamation mark should not be used.',
  68310. [new CodeSample("<?php\n\$a = !!\$b;\n")]
  68311. );
  68312. }
  68313. public function isCandidate(Tokens $tokens): bool
  68314. {
  68315. return $tokens->isTokenKindFound('!');
  68316. }
  68317. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68318. {
  68319. for ($index = \count($tokens) - 1; $index > 1; --$index) {
  68320. if ($tokens[$index]->equals('!')) {
  68321. $index = $this->fixShortCast($tokens, $index);
  68322. }
  68323. }
  68324. }
  68325. private function fixShortCast(Tokens $tokens, int $index): int
  68326. {
  68327. for ($i = $index - 1; $i > 1; --$i) {
  68328. if ($tokens[$i]->equals('!')) {
  68329. $this->fixShortCastToBoolCast($tokens, $i, $index);
  68330. break;
  68331. }
  68332. if (!$tokens[$i]->isComment() && !$tokens[$i]->isWhitespace()) {
  68333. break;
  68334. }
  68335. }
  68336. return $i;
  68337. }
  68338. private function fixShortCastToBoolCast(Tokens $tokens, int $start, int $end): void
  68339. {
  68340. for (; $start <= $end; ++$start) {
  68341. if (
  68342. !$tokens[$start]->isComment()
  68343. && !($tokens[$start]->isWhitespace() && $tokens[$start - 1]->isComment())
  68344. ) {
  68345. $tokens->clearAt($start);
  68346. }
  68347. }
  68348. $tokens->insertAt($start, new Token([T_BOOL_CAST, '(bool)']));
  68349. }
  68350. }
  68351. <?php
  68352. declare(strict_types=1);
  68353. namespace PhpCsFixer\Fixer\CastNotation;
  68354. use PhpCsFixer\AbstractFixer;
  68355. use PhpCsFixer\FixerDefinition\CodeSample;
  68356. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68357. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68358. use PhpCsFixer\Tokenizer\Token;
  68359. use PhpCsFixer\Tokenizer\Tokens;
  68360. final class ShortScalarCastFixer extends AbstractFixer
  68361. {
  68362. public function getDefinition(): FixerDefinitionInterface
  68363. {
  68364. return new FixerDefinition(
  68365. 'Cast `(boolean)` and `(integer)` should be written as `(bool)` and `(int)`, `(double)` and `(real)` as `(float)`, `(binary)` as `(string)`.',
  68366. [
  68367. new CodeSample(
  68368. "<?php\n\$a = (boolean) \$b;\n\$a = (integer) \$b;\n\$a = (double) \$b;\n\n\$a = (binary) \$b;\n",
  68369. ),
  68370. ]
  68371. );
  68372. }
  68373. public function isCandidate(Tokens $tokens): bool
  68374. {
  68375. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  68376. }
  68377. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68378. {
  68379. static $castMap = [
  68380. 'boolean' => 'bool',
  68381. 'integer' => 'int',
  68382. 'double' => 'float',
  68383. 'real' => 'float',
  68384. 'binary' => 'string',
  68385. ];
  68386. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  68387. if (!$tokens[$index]->isCast()) {
  68388. continue;
  68389. }
  68390. $castFrom = trim(substr($tokens[$index]->getContent(), 1, -1));
  68391. $castFromLowered = strtolower($castFrom);
  68392. if (!\array_key_exists($castFromLowered, $castMap)) {
  68393. continue;
  68394. }
  68395. $tokens[$index] = new Token([
  68396. $tokens[$index]->getId(),
  68397. str_replace($castFrom, $castMap[$castFromLowered], $tokens[$index]->getContent()),
  68398. ]);
  68399. }
  68400. }
  68401. }
  68402. <?php
  68403. declare(strict_types=1);
  68404. namespace PhpCsFixer\Fixer\CastNotation;
  68405. use PhpCsFixer\AbstractFunctionReferenceFixer;
  68406. use PhpCsFixer\FixerDefinition\CodeSample;
  68407. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68408. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68409. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  68410. use PhpCsFixer\Tokenizer\Token;
  68411. use PhpCsFixer\Tokenizer\Tokens;
  68412. final class ModernizeTypesCastingFixer extends AbstractFunctionReferenceFixer
  68413. {
  68414. public function getDefinition(): FixerDefinitionInterface
  68415. {
  68416. return new FixerDefinition(
  68417. 'Replaces `intval`, `floatval`, `doubleval`, `strval` and `boolval` function calls with according type casting operator.',
  68418. [
  68419. new CodeSample(
  68420. '<?php
  68421. $a = intval($b);
  68422. $a = floatval($b);
  68423. $a = doubleval($b);
  68424. $a = strval ($b);
  68425. $a = boolval($b);
  68426. '
  68427. ),
  68428. ],
  68429. null,
  68430. 'Risky if any of the functions `intval`, `floatval`, `doubleval`, `strval` or `boolval` are overridden.'
  68431. );
  68432. }
  68433. public function getPriority(): int
  68434. {
  68435. return 31;
  68436. }
  68437. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68438. {
  68439. static $replacement = [
  68440. 'intval' => [T_INT_CAST, '(int)'],
  68441. 'floatval' => [T_DOUBLE_CAST, '(float)'],
  68442. 'doubleval' => [T_DOUBLE_CAST, '(float)'],
  68443. 'strval' => [T_STRING_CAST, '(string)'],
  68444. 'boolval' => [T_BOOL_CAST, '(bool)'],
  68445. ];
  68446. $argumentsAnalyzer = new ArgumentsAnalyzer();
  68447. foreach ($replacement as $functionIdentity => $newToken) {
  68448. $currIndex = 0;
  68449. do {
  68450. $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
  68451. if (null === $boundaries) {
  68452. continue 2;
  68453. }
  68454. [$functionName, $openParenthesis, $closeParenthesis] = $boundaries;
  68455. $currIndex = $openParenthesis;
  68456. if (1 !== $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis)) {
  68457. continue;
  68458. }
  68459. $paramContentEnd = $closeParenthesis;
  68460. $commaCandidate = $tokens->getPrevMeaningfulToken($paramContentEnd);
  68461. if ($tokens[$commaCandidate]->equals(',')) {
  68462. $tokens->removeTrailingWhitespace($commaCandidate);
  68463. $tokens->clearAt($commaCandidate);
  68464. $paramContentEnd = $commaCandidate;
  68465. }
  68466. $countParamTokens = 0;
  68467. for ($paramContentIndex = $openParenthesis + 1; $paramContentIndex < $paramContentEnd; ++$paramContentIndex) {
  68468. if (!$tokens[$paramContentIndex]->isGivenKind(T_WHITESPACE)) {
  68469. ++$countParamTokens;
  68470. }
  68471. }
  68472. $preserveParentheses = $countParamTokens > 1;
  68473. $afterCloseParenthesisIndex = $tokens->getNextMeaningfulToken($closeParenthesis);
  68474. $afterCloseParenthesisToken = $tokens[$afterCloseParenthesisIndex];
  68475. $wrapInParentheses = $afterCloseParenthesisToken->equalsAny(['[', '{']) || $afterCloseParenthesisToken->isGivenKind(T_POW);
  68476. $prevTokenIndex = $tokens->getPrevMeaningfulToken($functionName);
  68477. if ($tokens[$prevTokenIndex]->isGivenKind(T_NS_SEPARATOR)) {
  68478. $tokens->removeTrailingWhitespace($prevTokenIndex);
  68479. $tokens->clearAt($prevTokenIndex);
  68480. }
  68481. $replacementSequence = [
  68482. new Token($newToken),
  68483. new Token([T_WHITESPACE, ' ']),
  68484. ];
  68485. if ($wrapInParentheses) {
  68486. array_unshift($replacementSequence, new Token('('));
  68487. }
  68488. if (!$preserveParentheses) {
  68489. $tokens->removeLeadingWhitespace($closeParenthesis);
  68490. $tokens->clearAt($closeParenthesis);
  68491. $tokens->removeLeadingWhitespace($openParenthesis);
  68492. $tokens->removeTrailingWhitespace($openParenthesis);
  68493. $tokens->clearAt($openParenthesis);
  68494. } else {
  68495. $tokens->removeTrailingWhitespace($functionName);
  68496. }
  68497. if ($wrapInParentheses) {
  68498. $tokens->insertAt($closeParenthesis, new Token(')'));
  68499. }
  68500. $tokens->overrideRange($functionName, $functionName, $replacementSequence);
  68501. $currIndex = $functionName;
  68502. } while (null !== $currIndex);
  68503. }
  68504. }
  68505. }
  68506. <?php
  68507. declare(strict_types=1);
  68508. namespace PhpCsFixer\Fixer\CastNotation;
  68509. use PhpCsFixer\AbstractFixer;
  68510. use PhpCsFixer\FixerDefinition\CodeSample;
  68511. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68512. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68513. use PhpCsFixer\Tokenizer\Token;
  68514. use PhpCsFixer\Tokenizer\Tokens;
  68515. final class LowercaseCastFixer extends AbstractFixer
  68516. {
  68517. public function getDefinition(): FixerDefinitionInterface
  68518. {
  68519. return new FixerDefinition(
  68520. 'Cast should be written in lower case.',
  68521. [
  68522. new CodeSample(
  68523. '<?php
  68524. $a = (BOOLEAN) $b;
  68525. $a = (BOOL) $b;
  68526. $a = (INTEGER) $b;
  68527. $a = (INT) $b;
  68528. $a = (DOUBLE) $b;
  68529. $a = (FLoaT) $b;
  68530. $a = (flOAT) $b;
  68531. $a = (sTRING) $b;
  68532. $a = (ARRAy) $b;
  68533. $a = (OBJect) $b;
  68534. $a = (UNset) $b;
  68535. $a = (Binary) $b;
  68536. ',
  68537. ),
  68538. ]
  68539. );
  68540. }
  68541. public function isCandidate(Tokens $tokens): bool
  68542. {
  68543. return $tokens->isAnyTokenKindsFound(Token::getCastTokenKinds());
  68544. }
  68545. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68546. {
  68547. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  68548. if (!$tokens[$index]->isCast()) {
  68549. continue;
  68550. }
  68551. $tokens[$index] = new Token([$tokens[$index]->getId(), strtolower($tokens[$index]->getContent())]);
  68552. }
  68553. }
  68554. }
  68555. <?php
  68556. declare(strict_types=1);
  68557. namespace PhpCsFixer\Fixer\Casing;
  68558. use PhpCsFixer\AbstractFixer;
  68559. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  68560. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  68561. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  68562. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  68563. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  68564. use PhpCsFixer\FixerDefinition\CodeSample;
  68565. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68566. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68567. use PhpCsFixer\Tokenizer\Token;
  68568. use PhpCsFixer\Tokenizer\Tokens;
  68569. /**
  68570. @phpstan-type
  68571. @phpstan-type
  68572. @implements
  68573. */
  68574. final class ConstantCaseFixer extends AbstractFixer implements ConfigurableFixerInterface
  68575. {
  68576. /**
  68577. @use */
  68578. use ConfigurableFixerTrait;
  68579. private $fixFunction;
  68580. public function getDefinition(): FixerDefinitionInterface
  68581. {
  68582. return new FixerDefinition(
  68583. 'The PHP constants `true`, `false`, and `null` MUST be written using the correct casing.',
  68584. [
  68585. new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n"),
  68586. new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n", ['case' => 'upper']),
  68587. ]
  68588. );
  68589. }
  68590. public function isCandidate(Tokens $tokens): bool
  68591. {
  68592. return $tokens->isTokenKindFound(T_STRING);
  68593. }
  68594. protected function configurePostNormalisation(): void
  68595. {
  68596. if ('lower' === $this->configuration['case']) {
  68597. $this->fixFunction = static fn (string $content): string => strtolower($content);
  68598. }
  68599. if ('upper' === $this->configuration['case']) {
  68600. $this->fixFunction = static fn (string $content): string => strtoupper($content);
  68601. }
  68602. }
  68603. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  68604. {
  68605. return new FixerConfigurationResolver([
  68606. (new FixerOptionBuilder('case', 'Whether to use the `upper` or `lower` case syntax.'))
  68607. ->setAllowedValues(['upper', 'lower'])
  68608. ->setDefault('lower')
  68609. ->getOption(),
  68610. ]);
  68611. }
  68612. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68613. {
  68614. static $forbiddenPrevKinds = null;
  68615. if (null === $forbiddenPrevKinds) {
  68616. $forbiddenPrevKinds = [
  68617. T_DOUBLE_COLON,
  68618. T_EXTENDS,
  68619. T_IMPLEMENTS,
  68620. T_INSTANCEOF,
  68621. T_NAMESPACE,
  68622. T_NEW,
  68623. T_NS_SEPARATOR,
  68624. ...Token::getObjectOperatorKinds(),
  68625. ];
  68626. }
  68627. foreach ($tokens as $index => $token) {
  68628. if (!$token->equalsAny([[T_STRING, 'true'], [T_STRING, 'false'], [T_STRING, 'null']], false)) {
  68629. continue;
  68630. }
  68631. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  68632. if ($tokens[$prevIndex]->isGivenKind($forbiddenPrevKinds)) {
  68633. continue;
  68634. }
  68635. $nextIndex = $tokens->getNextMeaningfulToken($index);
  68636. if ($tokens[$nextIndex]->isGivenKind([T_PAAMAYIM_NEKUDOTAYIM, T_NS_SEPARATOR]) || $tokens[$nextIndex]->equalsAny(['='], false)) {
  68637. continue;
  68638. }
  68639. if ($tokens[$prevIndex]->isGivenKind(T_CASE) && $tokens[$nextIndex]->equals(';')) {
  68640. continue;
  68641. }
  68642. $tokens[$index] = new Token([$token->getId(), ($this->fixFunction)($token->getContent())]);
  68643. }
  68644. }
  68645. }
  68646. <?php
  68647. declare(strict_types=1);
  68648. namespace PhpCsFixer\Fixer\Casing;
  68649. use PhpCsFixer\AbstractFixer;
  68650. use PhpCsFixer\FixerDefinition\CodeSample;
  68651. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68652. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68653. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  68654. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  68655. use PhpCsFixer\Tokenizer\CT;
  68656. use PhpCsFixer\Tokenizer\FCT;
  68657. use PhpCsFixer\Tokenizer\Token;
  68658. use PhpCsFixer\Tokenizer\Tokens;
  68659. final class ClassReferenceNameCasingFixer extends AbstractFixer
  68660. {
  68661. private const NOT_BEFORE_KINDS = [
  68662. CT::T_USE_TRAIT,
  68663. T_AS,
  68664. T_CASE,
  68665. T_CLASS,
  68666. T_CONST,
  68667. T_DOUBLE_ARROW,
  68668. T_DOUBLE_COLON,
  68669. T_FUNCTION,
  68670. T_INTERFACE,
  68671. T_OBJECT_OPERATOR,
  68672. T_TRAIT,
  68673. FCT::T_NULLSAFE_OBJECT_OPERATOR,
  68674. FCT::T_ENUM,
  68675. ];
  68676. public function getDefinition(): FixerDefinitionInterface
  68677. {
  68678. return new FixerDefinition(
  68679. 'When referencing an internal class it must be written using the correct casing.',
  68680. [
  68681. new CodeSample("<?php\nthrow new \\exception();\n"),
  68682. ]
  68683. );
  68684. }
  68685. public function isCandidate(Tokens $tokens): bool
  68686. {
  68687. return $tokens->isTokenKindFound(T_STRING);
  68688. }
  68689. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68690. {
  68691. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  68692. $classNames = $this->getClassNames();
  68693. foreach ($tokens->getNamespaceDeclarations() as $namespace) {
  68694. $uses = [];
  68695. foreach ($namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace) as $use) {
  68696. $uses[strtolower($use->getShortName())] = true;
  68697. }
  68698. foreach ($this->getClassReference($tokens, $namespace) as $reference) {
  68699. $currentContent = $tokens[$reference]->getContent();
  68700. $lowerCurrentContent = strtolower($currentContent);
  68701. if (isset($classNames[$lowerCurrentContent]) && $currentContent !== $classNames[$lowerCurrentContent] && !isset($uses[$lowerCurrentContent])) {
  68702. $tokens[$reference] = new Token([T_STRING, $classNames[$lowerCurrentContent]]);
  68703. }
  68704. }
  68705. }
  68706. }
  68707. private function getClassReference(Tokens $tokens, NamespaceAnalysis $namespace): \Generator
  68708. {
  68709. static $blockKinds;
  68710. if (null === $blockKinds) {
  68711. $blockKinds = ['before' => [','], 'after' => [',']];
  68712. foreach (Tokens::getBlockEdgeDefinitions() as $definition) {
  68713. $blockKinds['before'][] = $definition['start'];
  68714. $blockKinds['after'][] = $definition['end'];
  68715. }
  68716. }
  68717. $namespaceIsGlobal = $namespace->isGlobalNamespace();
  68718. for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
  68719. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  68720. continue;
  68721. }
  68722. $nextIndex = $tokens->getNextMeaningfulToken($index);
  68723. if ($tokens[$nextIndex]->isGivenKind(T_NS_SEPARATOR)) {
  68724. continue;
  68725. }
  68726. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  68727. $nextIndex = $tokens->getNextMeaningfulToken($index);
  68728. $isNamespaceSeparator = $tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR);
  68729. if (!$isNamespaceSeparator && !$namespaceIsGlobal) {
  68730. continue;
  68731. }
  68732. if ($isNamespaceSeparator) {
  68733. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  68734. if ($tokens[$prevIndex]->isGivenKind(T_STRING)) {
  68735. continue;
  68736. }
  68737. } elseif ($tokens[$prevIndex]->isGivenKind(self::NOT_BEFORE_KINDS)) {
  68738. continue;
  68739. }
  68740. if ($tokens[$prevIndex]->equalsAny($blockKinds['before']) && $tokens[$nextIndex]->equalsAny($blockKinds['after'])) {
  68741. continue;
  68742. }
  68743. if (!$tokens[$prevIndex]->isGivenKind(T_NEW) && $tokens[$nextIndex]->equalsAny(['(', ';', [T_CLOSE_TAG]])) {
  68744. continue;
  68745. }
  68746. yield $index;
  68747. }
  68748. }
  68749. private function getClassNames(): array
  68750. {
  68751. static $classes = null;
  68752. if (null === $classes) {
  68753. $classes = [];
  68754. foreach (get_declared_classes() as $class) {
  68755. if ((new \ReflectionClass($class))->isInternal()) {
  68756. $classes[strtolower($class)] = $class;
  68757. }
  68758. }
  68759. }
  68760. return $classes;
  68761. }
  68762. }
  68763. <?php
  68764. declare(strict_types=1);
  68765. namespace PhpCsFixer\Fixer\Casing;
  68766. use PhpCsFixer\AbstractFixer;
  68767. use PhpCsFixer\FixerDefinition\CodeSample;
  68768. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68769. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68770. use PhpCsFixer\Tokenizer\CT;
  68771. use PhpCsFixer\Tokenizer\Token;
  68772. use PhpCsFixer\Tokenizer\Tokens;
  68773. final class LowercaseStaticReferenceFixer extends AbstractFixer
  68774. {
  68775. public function getDefinition(): FixerDefinitionInterface
  68776. {
  68777. return new FixerDefinition(
  68778. 'Class static references `self`, `static` and `parent` MUST be in lower case.',
  68779. [
  68780. new CodeSample('<?php
  68781. class Foo extends Bar
  68782. {
  68783. public function baz1()
  68784. {
  68785. return STATIC::baz2();
  68786. }
  68787. public function baz2($x)
  68788. {
  68789. return $x instanceof Self;
  68790. }
  68791. public function baz3(PaRent $x)
  68792. {
  68793. return true;
  68794. }
  68795. }
  68796. '),
  68797. new CodeSample(
  68798. '<?php
  68799. class Foo extends Bar
  68800. {
  68801. public function baz(?self $x) : SELF
  68802. {
  68803. return false;
  68804. }
  68805. }
  68806. '
  68807. ),
  68808. ]
  68809. );
  68810. }
  68811. public function isCandidate(Tokens $tokens): bool
  68812. {
  68813. return $tokens->isAnyTokenKindsFound([T_STATIC, T_STRING]);
  68814. }
  68815. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68816. {
  68817. foreach ($tokens as $index => $token) {
  68818. if (!$token->equalsAny([[T_STRING, 'self'], [T_STATIC, 'static'], [T_STRING, 'parent']], false)) {
  68819. continue;
  68820. }
  68821. if (!self::isTokenToFix($tokens, $index)) {
  68822. continue;
  68823. }
  68824. $tokens[$index] = new Token([$token->getId(), strtolower($token->getContent())]);
  68825. }
  68826. }
  68827. private static function isTokenToFix(Tokens $tokens, int $index): bool
  68828. {
  68829. if ($tokens[$index]->getContent() === strtolower($tokens[$index]->getContent())) {
  68830. return false;
  68831. }
  68832. $nextIndex = $tokens->getNextMeaningfulToken($index);
  68833. if ($tokens[$nextIndex]->isGivenKind(T_DOUBLE_COLON)) {
  68834. return true;
  68835. }
  68836. if (!$tokens[$nextIndex]->isGivenKind([T_VARIABLE, CT::T_TYPE_ALTERNATION]) && !$tokens[$nextIndex]->equalsAny(['(', ')', '{', ';'])) {
  68837. return false;
  68838. }
  68839. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  68840. if ($tokens[$prevIndex]->isGivenKind(T_INSTANCEOF)) {
  68841. return true;
  68842. }
  68843. if ($tokens[$prevIndex]->isGivenKind(T_CASE)) {
  68844. return !$tokens[$nextIndex]->equals(';');
  68845. }
  68846. if (!$tokens[$prevIndex]->isGivenKind([T_NEW, T_PRIVATE, T_PROTECTED, T_PUBLIC, CT::T_NULLABLE_TYPE, CT::T_TYPE_COLON, CT::T_TYPE_ALTERNATION]) && !$tokens[$prevIndex]->equalsAny(['(', '{'])) {
  68847. return false;
  68848. }
  68849. if ($tokens[$prevIndex]->equals('(') && $tokens[$nextIndex]->equals(')')) {
  68850. return false;
  68851. }
  68852. if ('static' === strtolower($tokens[$index]->getContent()) && $tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  68853. return false;
  68854. }
  68855. return true;
  68856. }
  68857. }
  68858. <?php
  68859. declare(strict_types=1);
  68860. namespace PhpCsFixer\Fixer\Casing;
  68861. use PhpCsFixer\AbstractFixer;
  68862. use PhpCsFixer\FixerDefinition\CodeSample;
  68863. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68864. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68865. use PhpCsFixer\Preg;
  68866. use PhpCsFixer\Tokenizer\Token;
  68867. use PhpCsFixer\Tokenizer\Tokens;
  68868. final class IntegerLiteralCaseFixer extends AbstractFixer
  68869. {
  68870. public function getDefinition(): FixerDefinitionInterface
  68871. {
  68872. return new FixerDefinition(
  68873. 'Integer literals must be in correct case.',
  68874. [
  68875. new CodeSample(
  68876. "<?php\n\$foo = 0Xff;\n\$bar = 0B11111111;\n"
  68877. ),
  68878. ]
  68879. );
  68880. }
  68881. public function isCandidate(Tokens $tokens): bool
  68882. {
  68883. return $tokens->isTokenKindFound(T_LNUMBER);
  68884. }
  68885. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68886. {
  68887. foreach ($tokens as $index => $token) {
  68888. if (!$token->isGivenKind(T_LNUMBER)) {
  68889. continue;
  68890. }
  68891. $content = $token->getContent();
  68892. $newContent = Preg::replaceCallback('#^0([boxBOX])([0-9a-fA-F_]+)$#', static fn ($matches) => '0'.strtolower($matches[1]).strtoupper($matches[2]), $content);
  68893. if ($content === $newContent) {
  68894. continue;
  68895. }
  68896. $tokens[$index] = new Token([T_LNUMBER, $newContent]);
  68897. }
  68898. }
  68899. }
  68900. <?php
  68901. declare(strict_types=1);
  68902. namespace PhpCsFixer\Fixer\Casing;
  68903. use PhpCsFixer\AbstractFixer;
  68904. use PhpCsFixer\FixerDefinition\CodeSample;
  68905. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68906. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68907. use PhpCsFixer\Tokenizer\Token;
  68908. use PhpCsFixer\Tokenizer\Tokens;
  68909. final class LowercaseKeywordsFixer extends AbstractFixer
  68910. {
  68911. public function getDefinition(): FixerDefinitionInterface
  68912. {
  68913. return new FixerDefinition(
  68914. 'PHP keywords MUST be in lower case.',
  68915. [
  68916. new CodeSample(
  68917. '<?php
  68918. FOREACH($a AS $B) {
  68919. TRY {
  68920. NEW $C($a, ISSET($B));
  68921. WHILE($B) {
  68922. INCLUDE "test.php";
  68923. }
  68924. } CATCH(\Exception $e) {
  68925. EXIT(1);
  68926. }
  68927. }
  68928. '
  68929. ),
  68930. ]
  68931. );
  68932. }
  68933. public function isCandidate(Tokens $tokens): bool
  68934. {
  68935. return $tokens->isAnyTokenKindsFound(Token::getKeywords());
  68936. }
  68937. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  68938. {
  68939. foreach ($tokens as $index => $token) {
  68940. if ($token->isKeyword() && !$token->isGivenKind([T_HALT_COMPILER])) {
  68941. $tokens[$index] = new Token([$token->getId(), strtolower($token->getContent())]);
  68942. }
  68943. }
  68944. }
  68945. }
  68946. <?php
  68947. declare(strict_types=1);
  68948. namespace PhpCsFixer\Fixer\Casing;
  68949. use PhpCsFixer\AbstractProxyFixer;
  68950. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  68951. use PhpCsFixer\FixerDefinition\CodeSample;
  68952. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68953. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68954. final class NativeFunctionTypeDeclarationCasingFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  68955. {
  68956. public function getDefinition(): FixerDefinitionInterface
  68957. {
  68958. return new FixerDefinition(
  68959. 'Native type declarations for functions should use the correct case.',
  68960. [
  68961. new CodeSample("<?php\nclass Bar {\n public function Foo(CALLABLE \$bar)\n {\n return 1;\n }\n}\n"),
  68962. new CodeSample(
  68963. "<?php\nfunction Foo(INT \$a): Bool\n{\n return true;\n}\n"
  68964. ),
  68965. new CodeSample(
  68966. "<?php\nfunction Foo(Iterable \$a): VOID\n{\n echo 'Hello world';\n}\n"
  68967. ),
  68968. new CodeSample(
  68969. "<?php\nfunction Foo(Object \$a)\n{\n return 'hi!';\n}\n",
  68970. ),
  68971. ]
  68972. );
  68973. }
  68974. public function getSuccessorsNames(): array
  68975. {
  68976. return array_keys($this->proxyFixers);
  68977. }
  68978. protected function createProxyFixers(): array
  68979. {
  68980. $fixer = new NativeTypeDeclarationCasingFixer();
  68981. return [$fixer];
  68982. }
  68983. }
  68984. <?php
  68985. declare(strict_types=1);
  68986. namespace PhpCsFixer\Fixer\Casing;
  68987. use PhpCsFixer\AbstractFixer;
  68988. use PhpCsFixer\FixerDefinition\CodeSample;
  68989. use PhpCsFixer\FixerDefinition\FixerDefinition;
  68990. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  68991. use PhpCsFixer\Tokenizer\CT;
  68992. use PhpCsFixer\Tokenizer\FCT;
  68993. use PhpCsFixer\Tokenizer\Token;
  68994. use PhpCsFixer\Tokenizer\Tokens;
  68995. final class MagicConstantCasingFixer extends AbstractFixer
  68996. {
  68997. public function getDefinition(): FixerDefinitionInterface
  68998. {
  68999. return new FixerDefinition(
  69000. 'Magic constants should be referred to using the correct casing.',
  69001. [new CodeSample("<?php\necho __dir__;\n")]
  69002. );
  69003. }
  69004. public function isCandidate(Tokens $tokens): bool
  69005. {
  69006. return $tokens->isAnyTokenKindsFound($this->getMagicConstantTokens());
  69007. }
  69008. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69009. {
  69010. $magicConstants = $this->getMagicConstants();
  69011. $magicConstantTokens = $this->getMagicConstantTokens();
  69012. foreach ($tokens as $index => $token) {
  69013. if ($token->isGivenKind($magicConstantTokens)) {
  69014. $tokens[$index] = new Token([$token->getId(), $magicConstants[$token->getId()]]);
  69015. }
  69016. }
  69017. }
  69018. private function getMagicConstants(): array
  69019. {
  69020. static $magicConstants = null;
  69021. if (null === $magicConstants) {
  69022. $magicConstants = [
  69023. T_LINE => '__LINE__',
  69024. T_FILE => '__FILE__',
  69025. T_DIR => '__DIR__',
  69026. T_FUNC_C => '__FUNCTION__',
  69027. T_CLASS_C => '__CLASS__',
  69028. T_METHOD_C => '__METHOD__',
  69029. T_NS_C => '__NAMESPACE__',
  69030. CT::T_CLASS_CONSTANT => 'class',
  69031. T_TRAIT_C => '__TRAIT__',
  69032. FCT::T_PROPERTY_C => '__PROPERTY__',
  69033. ];
  69034. }
  69035. return $magicConstants;
  69036. }
  69037. private function getMagicConstantTokens(): array
  69038. {
  69039. static $magicConstantTokens = null;
  69040. if (null === $magicConstantTokens) {
  69041. $magicConstantTokens = array_keys($this->getMagicConstants());
  69042. }
  69043. return $magicConstantTokens;
  69044. }
  69045. }
  69046. <?php
  69047. declare(strict_types=1);
  69048. namespace PhpCsFixer\Fixer\Casing;
  69049. use PhpCsFixer\AbstractFixer;
  69050. use PhpCsFixer\FixerDefinition\CodeSample;
  69051. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69052. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69053. use PhpCsFixer\Tokenizer\Token;
  69054. use PhpCsFixer\Tokenizer\Tokens;
  69055. final class MagicMethodCasingFixer extends AbstractFixer
  69056. {
  69057. private const MAGIC_NAMES = [
  69058. '__call' => '__call',
  69059. '__callstatic' => '__callStatic',
  69060. '__clone' => '__clone',
  69061. '__construct' => '__construct',
  69062. '__debuginfo' => '__debugInfo',
  69063. '__destruct' => '__destruct',
  69064. '__get' => '__get',
  69065. '__invoke' => '__invoke',
  69066. '__isset' => '__isset',
  69067. '__serialize' => '__serialize',
  69068. '__set' => '__set',
  69069. '__set_state' => '__set_state',
  69070. '__sleep' => '__sleep',
  69071. '__tostring' => '__toString',
  69072. '__unserialize' => '__unserialize',
  69073. '__unset' => '__unset',
  69074. '__wakeup' => '__wakeup',
  69075. ];
  69076. public function getDefinition(): FixerDefinitionInterface
  69077. {
  69078. return new FixerDefinition(
  69079. 'Magic method definitions and calls must be using the correct casing.',
  69080. [
  69081. new CodeSample(
  69082. '<?php
  69083. class Foo
  69084. {
  69085. public function __Sleep()
  69086. {
  69087. }
  69088. }
  69089. '
  69090. ),
  69091. new CodeSample(
  69092. '<?php
  69093. $foo->__INVOKE(1);
  69094. '
  69095. ),
  69096. ]
  69097. );
  69098. }
  69099. public function isCandidate(Tokens $tokens): bool
  69100. {
  69101. return $tokens->isTokenKindFound(T_STRING) && $tokens->isAnyTokenKindsFound([T_FUNCTION, T_DOUBLE_COLON, ...Token::getObjectOperatorKinds()]);
  69102. }
  69103. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69104. {
  69105. $inClass = 0;
  69106. $tokenCount = \count($tokens);
  69107. for ($index = 1; $index < $tokenCount - 2; ++$index) {
  69108. if (0 === $inClass && $tokens[$index]->isClassy()) {
  69109. $inClass = 1;
  69110. $index = $tokens->getNextTokenOfKind($index, ['{']);
  69111. continue;
  69112. }
  69113. if (0 !== $inClass) {
  69114. if ($tokens[$index]->equals('{')) {
  69115. ++$inClass;
  69116. continue;
  69117. }
  69118. if ($tokens[$index]->equals('}')) {
  69119. --$inClass;
  69120. continue;
  69121. }
  69122. }
  69123. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  69124. continue;
  69125. }
  69126. $content = $tokens[$index]->getContent();
  69127. if (!str_starts_with($content, '__')) {
  69128. continue;
  69129. }
  69130. $name = strtolower($content);
  69131. if (!$this->isMagicMethodName($name)) {
  69132. continue;
  69133. }
  69134. $nameInCorrectCasing = $this->getMagicMethodNameInCorrectCasing($name);
  69135. if ($nameInCorrectCasing === $content) {
  69136. continue;
  69137. }
  69138. if ($this->isFunctionSignature($tokens, $index)) {
  69139. if (0 !== $inClass) {
  69140. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  69141. }
  69142. continue;
  69143. }
  69144. if ($this->isMethodCall($tokens, $index)) {
  69145. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  69146. continue;
  69147. }
  69148. if (
  69149. ('__callstatic' === $name || '__set_state' === $name)
  69150. && $this->isStaticMethodCall($tokens, $index)
  69151. ) {
  69152. $this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
  69153. }
  69154. }
  69155. }
  69156. private function isFunctionSignature(Tokens $tokens, int $index): bool
  69157. {
  69158. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  69159. if (!$tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
  69160. return false;
  69161. }
  69162. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  69163. }
  69164. private function isMethodCall(Tokens $tokens, int $index): bool
  69165. {
  69166. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  69167. if (!$tokens[$prevIndex]->isObjectOperator()) {
  69168. return false;
  69169. }
  69170. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  69171. }
  69172. private function isStaticMethodCall(Tokens $tokens, int $index): bool
  69173. {
  69174. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  69175. if (!$tokens[$prevIndex]->isGivenKind(T_DOUBLE_COLON)) {
  69176. return false;
  69177. }
  69178. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  69179. }
  69180. /**
  69181. @phpstan-assert-if-true
  69182. */
  69183. private function isMagicMethodName(string $name): bool
  69184. {
  69185. return isset(self::MAGIC_NAMES[$name]);
  69186. }
  69187. private function getMagicMethodNameInCorrectCasing(string $name): string
  69188. {
  69189. return self::MAGIC_NAMES[$name];
  69190. }
  69191. private function setTokenToCorrectCasing(Tokens $tokens, int $index, string $nameInCorrectCasing): void
  69192. {
  69193. $tokens[$index] = new Token([T_STRING, $nameInCorrectCasing]);
  69194. }
  69195. }
  69196. <?php
  69197. declare(strict_types=1);
  69198. namespace PhpCsFixer\Fixer\Casing;
  69199. use PhpCsFixer\AbstractFixer;
  69200. use PhpCsFixer\FixerDefinition\CodeSample;
  69201. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69202. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69203. use PhpCsFixer\FixerDefinition\VersionSpecification;
  69204. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  69205. use PhpCsFixer\Tokenizer\CT;
  69206. use PhpCsFixer\Tokenizer\Token;
  69207. use PhpCsFixer\Tokenizer\Tokens;
  69208. final class NativeTypeDeclarationCasingFixer extends AbstractFixer
  69209. {
  69210. private array $types;
  69211. public function __construct()
  69212. {
  69213. parent::__construct();
  69214. $this->types = [
  69215. 'array' => true,
  69216. 'bool' => true,
  69217. 'callable' => true,
  69218. 'float' => true,
  69219. 'int' => true,
  69220. 'iterable' => true,
  69221. 'object' => true,
  69222. 'parent' => true,
  69223. 'self' => true,
  69224. 'static' => true,
  69225. 'string' => true,
  69226. 'void' => true,
  69227. ];
  69228. if (\PHP_VERSION_ID >= 8_00_00) {
  69229. $this->types['false'] = true;
  69230. $this->types['mixed'] = true;
  69231. $this->types['null'] = true;
  69232. }
  69233. if (\PHP_VERSION_ID >= 8_01_00) {
  69234. $this->types['never'] = true;
  69235. }
  69236. if (\PHP_VERSION_ID >= 8_02_00) {
  69237. $this->types['true'] = true;
  69238. }
  69239. }
  69240. public function getDefinition(): FixerDefinitionInterface
  69241. {
  69242. return new FixerDefinition(
  69243. 'Native type declarations should be used in the correct case.',
  69244. [
  69245. new CodeSample(
  69246. "<?php\nclass Bar {\n public function Foo(CALLABLE \$bar): INT\n {\n return 1;\n }\n}\n"
  69247. ),
  69248. new VersionSpecificCodeSample(
  69249. "<?php\nclass Foo\n{\n const INT BAR = 1;\n}\n",
  69250. new VersionSpecification(8_03_00),
  69251. ),
  69252. ]
  69253. );
  69254. }
  69255. public function isCandidate(Tokens $tokens): bool
  69256. {
  69257. $classyFound = $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  69258. return
  69259. $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN])
  69260. || ($classyFound && $tokens->isTokenKindFound(T_STRING))
  69261. || (
  69262. \PHP_VERSION_ID >= 8_03_00
  69263. && $tokens->isTokenKindFound(T_CONST)
  69264. && $classyFound
  69265. );
  69266. }
  69267. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69268. {
  69269. foreach ($tokens as $index => $token) {
  69270. $content = $token->getContent();
  69271. $lowercaseContent = strtolower($content);
  69272. if ($content === $lowercaseContent) {
  69273. continue;
  69274. }
  69275. if (!isset($this->types[$lowercaseContent])) {
  69276. continue;
  69277. }
  69278. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  69279. if ($tokens[$prevIndex]->equals('=') || $tokens[$prevIndex]->isGivenKind([T_CASE, T_OBJECT_OPERATOR, T_DOUBLE_COLON, T_NS_SEPARATOR])) {
  69280. continue;
  69281. }
  69282. $nextIndex = $tokens->getNextMeaningfulToken($index);
  69283. if ($tokens[$nextIndex]->equals('=') || $tokens[$nextIndex]->isGivenKind(T_NS_SEPARATOR)) {
  69284. continue;
  69285. }
  69286. if (
  69287. !$tokens[$prevIndex]->isGivenKind([T_CONST, CT::T_NULLABLE_TYPE, CT::T_TYPE_ALTERNATION, CT::T_TYPE_COLON])
  69288. && !$tokens[$nextIndex]->isGivenKind([T_VARIABLE, CT::T_TYPE_ALTERNATION])
  69289. ) {
  69290. continue;
  69291. }
  69292. $tokens[$index] = new Token([$token->getId(), $lowercaseContent]);
  69293. }
  69294. }
  69295. }
  69296. <?php
  69297. declare(strict_types=1);
  69298. namespace PhpCsFixer\Fixer\Casing;
  69299. use PhpCsFixer\AbstractFixer;
  69300. use PhpCsFixer\FixerDefinition\CodeSample;
  69301. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69302. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69303. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  69304. use PhpCsFixer\Tokenizer\Token;
  69305. use PhpCsFixer\Tokenizer\Tokens;
  69306. final class NativeFunctionCasingFixer extends AbstractFixer
  69307. {
  69308. public function getDefinition(): FixerDefinitionInterface
  69309. {
  69310. return new FixerDefinition(
  69311. 'Function defined by PHP should be called using the correct casing.',
  69312. [new CodeSample("<?php\nSTRLEN(\$str);\n")]
  69313. );
  69314. }
  69315. public function getPriority(): int
  69316. {
  69317. return 0;
  69318. }
  69319. public function isCandidate(Tokens $tokens): bool
  69320. {
  69321. return $tokens->isTokenKindFound(T_STRING);
  69322. }
  69323. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69324. {
  69325. $functionsAnalyzer = new FunctionsAnalyzer();
  69326. static $nativeFunctionNames = null;
  69327. if (null === $nativeFunctionNames) {
  69328. $nativeFunctionNames = $this->getNativeFunctionNames();
  69329. }
  69330. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  69331. if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  69332. continue;
  69333. }
  69334. $lower = strtolower($tokens[$index]->getContent());
  69335. if (!\array_key_exists($lower, $nativeFunctionNames)) {
  69336. continue;
  69337. }
  69338. $tokens[$index] = new Token([T_STRING, $nativeFunctionNames[$lower]]);
  69339. }
  69340. }
  69341. private function getNativeFunctionNames(): array
  69342. {
  69343. $allFunctions = get_defined_functions();
  69344. $functions = [];
  69345. foreach ($allFunctions['internal'] as $function) {
  69346. $functions[strtolower($function)] = $function;
  69347. }
  69348. return $functions;
  69349. }
  69350. }
  69351. <?php
  69352. declare(strict_types=1);
  69353. namespace PhpCsFixer\Fixer\Comment;
  69354. use PhpCsFixer\AbstractFixer;
  69355. use PhpCsFixer\FixerDefinition\CodeSample;
  69356. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69357. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69358. use PhpCsFixer\Preg;
  69359. use PhpCsFixer\Tokenizer\Tokens;
  69360. final class NoEmptyCommentFixer extends AbstractFixer
  69361. {
  69362. private const TYPE_HASH = 1;
  69363. private const TYPE_DOUBLE_SLASH = 2;
  69364. private const TYPE_SLASH_ASTERISK = 3;
  69365. public function getPriority(): int
  69366. {
  69367. return 2;
  69368. }
  69369. public function getDefinition(): FixerDefinitionInterface
  69370. {
  69371. return new FixerDefinition(
  69372. 'There should not be any empty comments.',
  69373. [new CodeSample("<?php\n//\n#\n/* */\n")]
  69374. );
  69375. }
  69376. public function isCandidate(Tokens $tokens): bool
  69377. {
  69378. return $tokens->isTokenKindFound(T_COMMENT);
  69379. }
  69380. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69381. {
  69382. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  69383. if (!$tokens[$index]->isGivenKind(T_COMMENT)) {
  69384. continue;
  69385. }
  69386. $blockInfo = $this->getCommentBlock($tokens, $index);
  69387. $blockStart = $blockInfo['blockStart'];
  69388. $index = $blockInfo['blockEnd'];
  69389. $isEmpty = $blockInfo['isEmpty'];
  69390. if (false === $isEmpty) {
  69391. continue;
  69392. }
  69393. for ($i = $blockStart; $i <= $index; ++$i) {
  69394. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  69395. }
  69396. }
  69397. }
  69398. private function getCommentBlock(Tokens $tokens, int $index): array
  69399. {
  69400. $commentType = $this->getCommentType($tokens[$index]->getContent());
  69401. $empty = $this->isEmptyComment($tokens[$index]->getContent());
  69402. if (self::TYPE_SLASH_ASTERISK === $commentType) {
  69403. return [
  69404. 'blockStart' => $index,
  69405. 'blockEnd' => $index,
  69406. 'isEmpty' => $empty,
  69407. ];
  69408. }
  69409. $start = $index;
  69410. $count = \count($tokens);
  69411. ++$index;
  69412. for (; $index < $count; ++$index) {
  69413. if ($tokens[$index]->isComment()) {
  69414. if ($commentType !== $this->getCommentType($tokens[$index]->getContent())) {
  69415. break;
  69416. }
  69417. if ($empty) {
  69418. $empty = $this->isEmptyComment($tokens[$index]->getContent());
  69419. }
  69420. continue;
  69421. }
  69422. if (!$tokens[$index]->isWhitespace() || $this->getLineBreakCount($tokens, $index, $index + 1) > 1) {
  69423. break;
  69424. }
  69425. }
  69426. return [
  69427. 'blockStart' => $start,
  69428. 'blockEnd' => $index - 1,
  69429. 'isEmpty' => $empty,
  69430. ];
  69431. }
  69432. private function getCommentType(string $content): int
  69433. {
  69434. if (str_starts_with($content, '#')) {
  69435. return self::TYPE_HASH;
  69436. }
  69437. if ('*' === $content[1]) {
  69438. return self::TYPE_SLASH_ASTERISK;
  69439. }
  69440. return self::TYPE_DOUBLE_SLASH;
  69441. }
  69442. private function getLineBreakCount(Tokens $tokens, int $whiteStart, int $whiteEnd): int
  69443. {
  69444. $lineCount = 0;
  69445. for ($i = $whiteStart; $i < $whiteEnd; ++$i) {
  69446. $lineCount += Preg::matchAll('/\R/u', $tokens[$i]->getContent());
  69447. }
  69448. return $lineCount;
  69449. }
  69450. private function isEmptyComment(string $content): bool
  69451. {
  69452. static $mapper = [
  69453. self::TYPE_HASH => '|^#\s*$|',
  69454. self::TYPE_SLASH_ASTERISK => '|^/\*[\s\*]*\*+/$|',
  69455. self::TYPE_DOUBLE_SLASH => '|^//\s*$|',
  69456. ];
  69457. $type = $this->getCommentType($content);
  69458. return Preg::match($mapper[$type], $content);
  69459. }
  69460. }
  69461. <?php
  69462. declare(strict_types=1);
  69463. namespace PhpCsFixer\Fixer\Comment;
  69464. use PhpCsFixer\AbstractFixer;
  69465. use PhpCsFixer\FixerDefinition\CodeSample;
  69466. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69467. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69468. use PhpCsFixer\Preg;
  69469. use PhpCsFixer\Tokenizer\Token;
  69470. use PhpCsFixer\Tokenizer\Tokens;
  69471. final class NoTrailingWhitespaceInCommentFixer extends AbstractFixer
  69472. {
  69473. public function getDefinition(): FixerDefinitionInterface
  69474. {
  69475. return new FixerDefinition(
  69476. 'There MUST be no trailing spaces inside comment or PHPDoc.',
  69477. [new CodeSample('<?php
  69478. // This is '.'
  69479. // a comment. '.'
  69480. ')]
  69481. );
  69482. }
  69483. public function getPriority(): int
  69484. {
  69485. return 0;
  69486. }
  69487. public function isCandidate(Tokens $tokens): bool
  69488. {
  69489. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  69490. }
  69491. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69492. {
  69493. foreach ($tokens as $index => $token) {
  69494. if ($token->isGivenKind(T_DOC_COMMENT)) {
  69495. $tokens[$index] = new Token([T_DOC_COMMENT, Preg::replace('/(*ANY)[\h]+$/m', '', $token->getContent())]);
  69496. continue;
  69497. }
  69498. if ($token->isGivenKind(T_COMMENT)) {
  69499. if (str_starts_with($token->getContent(), '/*')) {
  69500. $tokens[$index] = new Token([T_COMMENT, Preg::replace('/(*ANY)[\h]+$/m', '', $token->getContent())]);
  69501. } elseif (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
  69502. $trimmedContent = ltrim($tokens[$index + 1]->getContent(), " \t");
  69503. $tokens->ensureWhitespaceAtIndex($index + 1, 0, $trimmedContent);
  69504. }
  69505. }
  69506. }
  69507. }
  69508. }
  69509. <?php
  69510. declare(strict_types=1);
  69511. namespace PhpCsFixer\Fixer\Comment;
  69512. use PhpCsFixer\AbstractFixer;
  69513. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  69514. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  69515. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  69516. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  69517. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  69518. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  69519. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  69520. use PhpCsFixer\FixerDefinition\CodeSample;
  69521. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69522. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69523. use PhpCsFixer\Preg;
  69524. use PhpCsFixer\PregException;
  69525. use PhpCsFixer\Tokenizer\Token;
  69526. use PhpCsFixer\Tokenizer\Tokens;
  69527. use Symfony\Component\OptionsResolver\Options;
  69528. /**
  69529. @phpstan-type
  69530. @phpstan-type
  69531. @implements
  69532. */
  69533. final class HeaderCommentFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  69534. {
  69535. /**
  69536. @use */
  69537. use ConfigurableFixerTrait;
  69538. public const HEADER_PHPDOC = 'PHPDoc';
  69539. public const HEADER_COMMENT = 'comment';
  69540. public function getDefinition(): FixerDefinitionInterface
  69541. {
  69542. return new FixerDefinition(
  69543. 'Add, replace or remove header comment.',
  69544. [
  69545. new CodeSample(
  69546. '<?php
  69547. declare(strict_types=1);
  69548. namespace A\B;
  69549. echo 1;
  69550. ',
  69551. [
  69552. 'header' => 'Made with love.',
  69553. ]
  69554. ),
  69555. new CodeSample(
  69556. '<?php
  69557. declare(strict_types=1);
  69558. namespace A\B;
  69559. echo 1;
  69560. ',
  69561. [
  69562. 'header' => 'Made with love.',
  69563. 'comment_type' => self::HEADER_PHPDOC,
  69564. 'location' => 'after_open',
  69565. 'separate' => 'bottom',
  69566. ]
  69567. ),
  69568. new CodeSample(
  69569. '<?php
  69570. declare(strict_types=1);
  69571. namespace A\B;
  69572. echo 1;
  69573. ',
  69574. [
  69575. 'header' => 'Made with love.',
  69576. 'comment_type' => self::HEADER_COMMENT,
  69577. 'location' => 'after_declare_strict',
  69578. ]
  69579. ),
  69580. new CodeSample(
  69581. '<?php
  69582. declare(strict_types=1);
  69583. /*
  69584. * Made with love.
  69585. *
  69586. * Extra content.
  69587. */
  69588. namespace A\B;
  69589. echo 1;
  69590. ',
  69591. [
  69592. 'header' => 'Made with love.',
  69593. 'validator' => '/Made with love(?P<EXTRA>.*)??/s',
  69594. 'comment_type' => self::HEADER_COMMENT,
  69595. 'location' => 'after_declare_strict',
  69596. ]
  69597. ),
  69598. new CodeSample(
  69599. '<?php
  69600. declare(strict_types=1);
  69601. /*
  69602. * Comment is not wanted here.
  69603. */
  69604. namespace A\B;
  69605. echo 1;
  69606. ',
  69607. [
  69608. 'header' => '',
  69609. ]
  69610. ),
  69611. ]
  69612. );
  69613. }
  69614. public function isCandidate(Tokens $tokens): bool
  69615. {
  69616. return $tokens->isMonolithicPhp() && !$tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  69617. }
  69618. public function getPriority(): int
  69619. {
  69620. return -30;
  69621. }
  69622. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69623. {
  69624. $headerAsComment = $this->getHeaderAsComment();
  69625. $location = $this->configuration['location'];
  69626. $locationIndices = [];
  69627. foreach (['after_open', 'after_declare_strict'] as $possibleLocation) {
  69628. $locationIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);
  69629. if (!isset($locationIndices[$locationIndex]) || $possibleLocation === $location) {
  69630. $locationIndices[$locationIndex] = $possibleLocation;
  69631. }
  69632. }
  69633. if (null !== $this->configuration['validator']) {
  69634. foreach ($locationIndices as $possibleLocation) {
  69635. $headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);
  69636. $headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerAsComment, $headerNewIndex - 1);
  69637. if (null === $headerCurrentIndex) {
  69638. continue;
  69639. }
  69640. $currentHeaderComment = $tokens[$headerCurrentIndex]->getContent();
  69641. if ($this->doesTokenFulfillValidator($tokens[$headerCurrentIndex])) {
  69642. $headerAsComment = $currentHeaderComment;
  69643. }
  69644. }
  69645. }
  69646. foreach ($locationIndices as $possibleLocation) {
  69647. $headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);
  69648. $headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerAsComment, $headerNewIndex - 1);
  69649. if (null === $headerCurrentIndex) {
  69650. if ('' === $this->configuration['header'] || $possibleLocation !== $location) {
  69651. continue;
  69652. }
  69653. $this->insertHeader($tokens, $headerAsComment, $headerNewIndex);
  69654. continue;
  69655. }
  69656. $currentHeaderComment = $tokens[$headerCurrentIndex]->getContent();
  69657. $sameComment = $headerAsComment === $currentHeaderComment;
  69658. $expectedLocation = $possibleLocation === $location;
  69659. if (!$sameComment || !$expectedLocation) {
  69660. if ($expectedLocation xor $sameComment) {
  69661. $this->removeHeader($tokens, $headerCurrentIndex);
  69662. }
  69663. if ('' === $this->configuration['header']) {
  69664. continue;
  69665. }
  69666. if ($possibleLocation === $location) {
  69667. $this->insertHeader($tokens, $headerAsComment, $headerNewIndex);
  69668. }
  69669. continue;
  69670. }
  69671. $this->fixWhiteSpaceAroundHeader($tokens, $headerCurrentIndex);
  69672. }
  69673. }
  69674. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  69675. {
  69676. $fixerName = $this->getName();
  69677. return new FixerConfigurationResolver([
  69678. (new FixerOptionBuilder('header', 'Proper header content.'))
  69679. ->setAllowedTypes(['string'])
  69680. ->setNormalizer(static function (Options $options, string $value) use ($fixerName): string {
  69681. if ('' === trim($value)) {
  69682. return '';
  69683. }
  69684. if (str_contains($value, '*/')) {
  69685. throw new InvalidFixerConfigurationException($fixerName, 'Cannot use \'*/\' in header.');
  69686. }
  69687. return $value;
  69688. })
  69689. ->getOption(),
  69690. (new FixerOptionBuilder('validator', 'RegEx validator for header content.'))
  69691. ->setAllowedTypes(['string', 'null'])
  69692. ->setNormalizer(static function (Options $options, ?string $value) use ($fixerName): ?string {
  69693. if (null !== $value) {
  69694. try {
  69695. Preg::match($value, '');
  69696. } catch (PregException $exception) {
  69697. throw new InvalidFixerConfigurationException($fixerName, 'Provided RegEx is not valid.');
  69698. }
  69699. }
  69700. return $value;
  69701. })
  69702. ->setDefault(null)
  69703. ->getOption(),
  69704. (new FixerOptionBuilder('comment_type', 'Comment syntax type.'))
  69705. ->setAllowedValues([self::HEADER_PHPDOC, self::HEADER_COMMENT])
  69706. ->setDefault(self::HEADER_COMMENT)
  69707. ->getOption(),
  69708. (new FixerOptionBuilder('location', 'The location of the inserted header.'))
  69709. ->setAllowedValues(['after_open', 'after_declare_strict'])
  69710. ->setDefault('after_declare_strict')
  69711. ->getOption(),
  69712. (new FixerOptionBuilder('separate', 'Whether the header should be separated from the file content with a new line.'))
  69713. ->setAllowedValues(['both', 'top', 'bottom', 'none'])
  69714. ->setDefault('both')
  69715. ->getOption(),
  69716. ]);
  69717. }
  69718. private function doesTokenFulfillValidator(Token $token): bool
  69719. {
  69720. if (null === $this->configuration['validator']) {
  69721. throw new \LogicException(\sprintf("Cannot call '%s' method while missing config:validator.", __METHOD__));
  69722. }
  69723. $currentHeaderComment = $token->getContent();
  69724. $lines = implode("\n", array_map(
  69725. static fn (string $line): string => ' *' === $line ? '' : (str_starts_with($line, ' * ') ? substr($line, 3) : $line),
  69726. \array_slice(explode("\n", $currentHeaderComment), 1, -1),
  69727. ));
  69728. return Preg::match($this->configuration['validator'], $lines);
  69729. }
  69730. private function getHeaderAsComment(): string
  69731. {
  69732. $lineEnding = $this->whitespacesConfig->getLineEnding();
  69733. $comment = (self::HEADER_COMMENT === $this->configuration['comment_type'] ? '/*' : '/**').$lineEnding;
  69734. $lines = explode("\n", str_replace("\r", '', $this->configuration['header']));
  69735. foreach ($lines as $line) {
  69736. $comment .= rtrim(' * '.$line).$lineEnding;
  69737. }
  69738. return $comment.' */';
  69739. }
  69740. private function findHeaderCommentCurrentIndex(Tokens $tokens, string $headerAsComment, int $headerNewIndex): ?int
  69741. {
  69742. $index = $tokens->getNextNonWhitespace($headerNewIndex);
  69743. if (null === $index || !$tokens[$index]->isComment()) {
  69744. return null;
  69745. }
  69746. $next = $index + 1;
  69747. if (!isset($tokens[$next]) || \in_array($this->configuration['separate'], ['top', 'none'], true) || !$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  69748. return $index;
  69749. }
  69750. if ($tokens[$next]->isWhitespace()) {
  69751. if (!Preg::match('/^\h*\R\h*$/D', $tokens[$next]->getContent())) {
  69752. return $index;
  69753. }
  69754. ++$next;
  69755. }
  69756. if (!isset($tokens[$next]) || !$tokens[$next]->isClassy() && !$tokens[$next]->isGivenKind(T_FUNCTION)) {
  69757. return $index;
  69758. }
  69759. if (
  69760. $headerAsComment === $tokens[$index]->getContent()
  69761. || (null !== $this->configuration['validator'] && $this->doesTokenFulfillValidator($tokens[$index]))
  69762. ) {
  69763. return $index;
  69764. }
  69765. return null;
  69766. }
  69767. private function findHeaderCommentInsertionIndex(Tokens $tokens, string $location): int
  69768. {
  69769. $openTagIndex = $tokens[0]->isGivenKind(T_INLINE_HTML) ? 1 : 0;
  69770. if ('after_open' === $location) {
  69771. return $openTagIndex + 1;
  69772. }
  69773. $index = $tokens->getNextMeaningfulToken($openTagIndex);
  69774. if (null === $index) {
  69775. return $openTagIndex + 1;
  69776. }
  69777. if (!$tokens[$index]->isGivenKind(T_DECLARE)) {
  69778. return $openTagIndex + 1;
  69779. }
  69780. $next = $tokens->getNextMeaningfulToken($index);
  69781. if (null === $next || !$tokens[$next]->equals('(')) {
  69782. return $openTagIndex + 1;
  69783. }
  69784. $next = $tokens->getNextMeaningfulToken($next);
  69785. if (null === $next || !$tokens[$next]->equals([T_STRING, 'strict_types'], false)) {
  69786. return $openTagIndex + 1;
  69787. }
  69788. $next = $tokens->getNextMeaningfulToken($next);
  69789. if (null === $next || !$tokens[$next]->equals('=')) {
  69790. return $openTagIndex + 1;
  69791. }
  69792. $next = $tokens->getNextMeaningfulToken($next);
  69793. if (null === $next || !$tokens[$next]->isGivenKind(T_LNUMBER)) {
  69794. return $openTagIndex + 1;
  69795. }
  69796. $next = $tokens->getNextMeaningfulToken($next);
  69797. if (null === $next || !$tokens[$next]->equals(')')) {
  69798. return $openTagIndex + 1;
  69799. }
  69800. $next = $tokens->getNextMeaningfulToken($next);
  69801. if (null === $next || !$tokens[$next]->equals(';')) {
  69802. return $openTagIndex + 1;
  69803. }
  69804. return $next + 1;
  69805. }
  69806. private function fixWhiteSpaceAroundHeader(Tokens $tokens, int $headerIndex): void
  69807. {
  69808. $lineEnding = $this->whitespacesConfig->getLineEnding();
  69809. if (
  69810. ('both' === $this->configuration['separate'] || 'bottom' === $this->configuration['separate'])
  69811. && null !== $tokens->getNextMeaningfulToken($headerIndex)
  69812. ) {
  69813. $expectedLineCount = 2;
  69814. } else {
  69815. $expectedLineCount = 1;
  69816. }
  69817. if ($headerIndex === \count($tokens) - 1) {
  69818. $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount)]));
  69819. } else {
  69820. $lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, 1);
  69821. if ($lineBreakCount < $expectedLineCount) {
  69822. $missing = str_repeat($lineEnding, $expectedLineCount - $lineBreakCount);
  69823. if ($tokens[$headerIndex + 1]->isWhitespace()) {
  69824. $tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $missing.$tokens[$headerIndex + 1]->getContent()]);
  69825. } else {
  69826. $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, $missing]));
  69827. }
  69828. } elseif ($lineBreakCount > $expectedLineCount && $tokens[$headerIndex + 1]->isWhitespace()) {
  69829. $newLinesToRemove = $lineBreakCount - $expectedLineCount;
  69830. $tokens[$headerIndex + 1] = new Token([
  69831. T_WHITESPACE,
  69832. Preg::replace("/^\\R{{$newLinesToRemove}}/", '', $tokens[$headerIndex + 1]->getContent()),
  69833. ]);
  69834. }
  69835. }
  69836. $expectedLineCount = 'both' === $this->configuration['separate'] || 'top' === $this->configuration['separate'] ? 2 : 1;
  69837. $prev = $tokens->getPrevNonWhitespace($headerIndex);
  69838. $regex = '/\h$/';
  69839. if ($tokens[$prev]->isGivenKind(T_OPEN_TAG) && Preg::match($regex, $tokens[$prev]->getContent())) {
  69840. $tokens[$prev] = new Token([T_OPEN_TAG, Preg::replace($regex, $lineEnding, $tokens[$prev]->getContent())]);
  69841. }
  69842. $lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, -1);
  69843. if ($lineBreakCount < $expectedLineCount) {
  69844. $tokens->insertAt($headerIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount - $lineBreakCount)]));
  69845. }
  69846. }
  69847. private function getLineBreakCount(Tokens $tokens, int $index, int $direction): int
  69848. {
  69849. $whitespace = '';
  69850. for ($index += $direction; isset($tokens[$index]); $index += $direction) {
  69851. $token = $tokens[$index];
  69852. if ($token->isWhitespace()) {
  69853. $whitespace .= $token->getContent();
  69854. continue;
  69855. }
  69856. if (-1 === $direction && $token->isGivenKind(T_OPEN_TAG)) {
  69857. $whitespace .= $token->getContent();
  69858. }
  69859. if ('' !== $token->getContent()) {
  69860. break;
  69861. }
  69862. }
  69863. return substr_count($whitespace, "\n");
  69864. }
  69865. private function removeHeader(Tokens $tokens, int $index): void
  69866. {
  69867. $prevIndex = $index - 1;
  69868. $prevToken = $tokens[$prevIndex];
  69869. $newlineRemoved = false;
  69870. if ($prevToken->isWhitespace()) {
  69871. $content = $prevToken->getContent();
  69872. if (Preg::match('/\R/', $content)) {
  69873. $newlineRemoved = true;
  69874. }
  69875. $content = Preg::replace('/\R?\h*$/', '', $content);
  69876. $tokens->ensureWhitespaceAtIndex($prevIndex, 0, $content);
  69877. }
  69878. $nextIndex = $index + 1;
  69879. $nextToken = $tokens[$nextIndex] ?? null;
  69880. if (!$newlineRemoved && null !== $nextToken && $nextToken->isWhitespace()) {
  69881. $content = Preg::replace('/^\R/', '', $nextToken->getContent());
  69882. $tokens->ensureWhitespaceAtIndex($nextIndex, 0, $content);
  69883. }
  69884. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  69885. }
  69886. private function insertHeader(Tokens $tokens, string $headerAsComment, int $index): void
  69887. {
  69888. $tokens->insertAt($index, new Token([self::HEADER_COMMENT === $this->configuration['comment_type'] ? T_COMMENT : T_DOC_COMMENT, $headerAsComment]));
  69889. $this->fixWhiteSpaceAroundHeader($tokens, $index);
  69890. }
  69891. }
  69892. <?php
  69893. declare(strict_types=1);
  69894. namespace PhpCsFixer\Fixer\Comment;
  69895. use PhpCsFixer\AbstractFixer;
  69896. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  69897. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  69898. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  69899. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  69900. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  69901. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  69902. use PhpCsFixer\FixerDefinition\CodeSample;
  69903. use PhpCsFixer\FixerDefinition\FixerDefinition;
  69904. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  69905. use PhpCsFixer\Preg;
  69906. use PhpCsFixer\Tokenizer\Analyzer\CommentsAnalyzer;
  69907. use PhpCsFixer\Tokenizer\Token;
  69908. use PhpCsFixer\Tokenizer\Tokens;
  69909. use PhpCsFixer\Utils;
  69910. /**
  69911. @phpstan-type
  69912. @phpstan-type
  69913. @implements
  69914. */
  69915. final class CommentToPhpdocFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  69916. {
  69917. /**
  69918. @use */
  69919. use ConfigurableFixerTrait;
  69920. private array $ignoredTags = [];
  69921. public function isCandidate(Tokens $tokens): bool
  69922. {
  69923. return $tokens->isTokenKindFound(T_COMMENT);
  69924. }
  69925. public function isRisky(): bool
  69926. {
  69927. return true;
  69928. }
  69929. public function getPriority(): int
  69930. {
  69931. return 26;
  69932. }
  69933. public function getDefinition(): FixerDefinitionInterface
  69934. {
  69935. return new FixerDefinition(
  69936. 'Comments with annotation should be docblock when used on structural elements.',
  69937. [
  69938. new CodeSample("<?php /* header */ \$x = true; /* @var bool \$isFoo */ \$isFoo = true;\n"),
  69939. new CodeSample("<?php\n// @todo do something later\n\$foo = 1;\n\n// @var int \$a\n\$a = foo();\n", ['ignored_tags' => ['todo']]),
  69940. ],
  69941. null,
  69942. 'Risky as new docblocks might mean more, e.g. a Doctrine entity might have a new column in database.'
  69943. );
  69944. }
  69945. protected function configurePostNormalisation(): void
  69946. {
  69947. $this->ignoredTags = array_map(
  69948. static fn (string $tag): string => strtolower($tag),
  69949. $this->configuration['ignored_tags']
  69950. );
  69951. }
  69952. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  69953. {
  69954. return new FixerConfigurationResolver([
  69955. (new FixerOptionBuilder('ignored_tags', 'List of ignored tags.'))
  69956. ->setAllowedTypes(['string[]'])
  69957. ->setDefault([])
  69958. ->getOption(),
  69959. ]);
  69960. }
  69961. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  69962. {
  69963. $commentsAnalyzer = new CommentsAnalyzer();
  69964. for ($index = 0, $limit = \count($tokens); $index < $limit; ++$index) {
  69965. $token = $tokens[$index];
  69966. if (!$token->isGivenKind(T_COMMENT)) {
  69967. continue;
  69968. }
  69969. if ($commentsAnalyzer->isHeaderComment($tokens, $index)) {
  69970. continue;
  69971. }
  69972. if (!$commentsAnalyzer->isBeforeStructuralElement($tokens, $index)) {
  69973. continue;
  69974. }
  69975. if (Preg::match('~(?:#|//|/\*+|\R(?:\s*\*)?)\s*\@(?=\w+-(ignore|suppress))([a-zA-Z0-9_\\\-]+)(?=\s|\(|$)~', $tokens[$index]->getContent())) {
  69976. continue;
  69977. }
  69978. $commentIndices = $commentsAnalyzer->getCommentBlockIndices($tokens, $index);
  69979. if ($this->isCommentCandidate($tokens, $commentIndices)) {
  69980. $this->fixComment($tokens, $commentIndices);
  69981. }
  69982. $index = max($commentIndices);
  69983. }
  69984. }
  69985. private function isCommentCandidate(Tokens $tokens, array $indices): bool
  69986. {
  69987. return array_reduce(
  69988. $indices,
  69989. function (bool $carry, int $index) use ($tokens): bool {
  69990. if ($carry) {
  69991. return true;
  69992. }
  69993. if (!Preg::match('~(?:#|//|/\*+|\R(?:\s*\*)?)\s*\@([a-zA-Z0-9_\\\-]+)(?=\s|\(|$)~', $tokens[$index]->getContent(), $matches)) {
  69994. return false;
  69995. }
  69996. return !\in_array(strtolower($matches[1]), $this->ignoredTags, true);
  69997. },
  69998. false
  69999. );
  70000. }
  70001. private function fixComment(Tokens $tokens, array $indices): void
  70002. {
  70003. if (1 === \count($indices)) {
  70004. $this->fixCommentSingleLine($tokens, $indices[0]);
  70005. } else {
  70006. $this->fixCommentMultiLine($tokens, $indices);
  70007. }
  70008. }
  70009. private function fixCommentSingleLine(Tokens $tokens, int $index): void
  70010. {
  70011. $message = $this->getMessage($tokens[$index]->getContent());
  70012. if ('' !== trim(substr($message, 0, 1))) {
  70013. $message = ' '.$message;
  70014. }
  70015. if ('' !== trim(substr($message, -1))) {
  70016. $message .= ' ';
  70017. }
  70018. $tokens[$index] = new Token([T_DOC_COMMENT, '/**'.$message.'*/']);
  70019. }
  70020. private function fixCommentMultiLine(Tokens $tokens, array $indices): void
  70021. {
  70022. $startIndex = $indices[0];
  70023. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$startIndex - 1]);
  70024. $newContent = '/**'.$this->whitespacesConfig->getLineEnding();
  70025. $count = max($indices);
  70026. for ($index = $startIndex; $index <= $count; ++$index) {
  70027. if (!$tokens[$index]->isComment()) {
  70028. continue;
  70029. }
  70030. if (str_contains($tokens[$index]->getContent(), '*/')) {
  70031. return;
  70032. }
  70033. $message = $this->getMessage($tokens[$index]->getContent());
  70034. if ('' !== trim(substr($message, 0, 1))) {
  70035. $message = ' '.$message;
  70036. }
  70037. $newContent .= $indent.' *'.$message.$this->whitespacesConfig->getLineEnding();
  70038. }
  70039. for ($index = $startIndex; $index <= $count; ++$index) {
  70040. $tokens->clearAt($index);
  70041. }
  70042. $newContent .= $indent.' */';
  70043. $tokens->insertAt($startIndex, new Token([T_DOC_COMMENT, $newContent]));
  70044. }
  70045. private function getMessage(string $content): string
  70046. {
  70047. if (str_starts_with($content, '#')) {
  70048. return substr($content, 1);
  70049. }
  70050. if (str_starts_with($content, '//')) {
  70051. return substr($content, 2);
  70052. }
  70053. return rtrim(ltrim($content, '/*'), '*/');
  70054. }
  70055. }
  70056. <?php
  70057. declare(strict_types=1);
  70058. namespace PhpCsFixer\Fixer\Comment;
  70059. use PhpCsFixer\AbstractFixer;
  70060. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  70061. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  70062. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  70063. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  70064. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  70065. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  70066. use PhpCsFixer\FixerDefinition\CodeSample;
  70067. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70068. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70069. use PhpCsFixer\Preg;
  70070. use PhpCsFixer\Tokenizer\Token;
  70071. use PhpCsFixer\Tokenizer\Tokens;
  70072. /**
  70073. @phpstan-type
  70074. @phpstan-type
  70075. @implements
  70076. */
  70077. final class SingleLineCommentStyleFixer extends AbstractFixer implements ConfigurableFixerInterface
  70078. {
  70079. /**
  70080. @use */
  70081. use ConfigurableFixerTrait;
  70082. private bool $asteriskEnabled;
  70083. private bool $hashEnabled;
  70084. public function getDefinition(): FixerDefinitionInterface
  70085. {
  70086. return new FixerDefinition(
  70087. 'Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.',
  70088. [
  70089. new CodeSample(
  70090. '<?php
  70091. /* asterisk comment */
  70092. $a = 1;
  70093. # hash comment
  70094. $b = 2;
  70095. /*
  70096. * multi-line
  70097. * comment
  70098. */
  70099. $c = 3;
  70100. '
  70101. ),
  70102. new CodeSample(
  70103. '<?php
  70104. /* first comment */
  70105. $a = 1;
  70106. /*
  70107. * second comment
  70108. */
  70109. $b = 2;
  70110. /*
  70111. * third
  70112. * comment
  70113. */
  70114. $c = 3;
  70115. ',
  70116. ['comment_types' => ['asterisk']]
  70117. ),
  70118. new CodeSample(
  70119. "<?php # comment\n",
  70120. ['comment_types' => ['hash']]
  70121. ),
  70122. ]
  70123. );
  70124. }
  70125. public function getPriority(): int
  70126. {
  70127. return -31;
  70128. }
  70129. public function isCandidate(Tokens $tokens): bool
  70130. {
  70131. return $tokens->isTokenKindFound(T_COMMENT);
  70132. }
  70133. protected function configurePostNormalisation(): void
  70134. {
  70135. $this->asteriskEnabled = \in_array('asterisk', $this->configuration['comment_types'], true);
  70136. $this->hashEnabled = \in_array('hash', $this->configuration['comment_types'], true);
  70137. }
  70138. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70139. {
  70140. foreach ($tokens as $index => $token) {
  70141. if (!$token->isGivenKind(T_COMMENT)) {
  70142. continue;
  70143. }
  70144. $content = $token->getContent();
  70145. $commentContent = substr($content, 2, -2) ?: '';
  70146. if ($this->hashEnabled && str_starts_with($content, '#')) {
  70147. if (isset($content[1]) && '[' === $content[1]) {
  70148. continue;
  70149. }
  70150. $tokens[$index] = new Token([$token->getId(), '//'.substr($content, 1)]);
  70151. continue;
  70152. }
  70153. if (
  70154. !$this->asteriskEnabled
  70155. || str_contains($commentContent, '?>')
  70156. || !str_starts_with($content, '/*')
  70157. || Preg::match('/[^\s\*].*\R.*[^\s\*]/s', $commentContent)
  70158. ) {
  70159. continue;
  70160. }
  70161. $nextTokenIndex = $index + 1;
  70162. if (isset($tokens[$nextTokenIndex])) {
  70163. $nextToken = $tokens[$nextTokenIndex];
  70164. if (!$nextToken->isWhitespace() || !Preg::match('/\R/', $nextToken->getContent())) {
  70165. continue;
  70166. }
  70167. $tokens[$nextTokenIndex] = new Token([$nextToken->getId(), ltrim($nextToken->getContent(), " \t")]);
  70168. }
  70169. $content = '//';
  70170. if (Preg::match('/[^\s\*]/', $commentContent)) {
  70171. $content = '// '.Preg::replace('/[\s\*]*([^\s\*](?:.+[^\s\*])?)[\s\*]*/', '\1', $commentContent);
  70172. }
  70173. $tokens[$index] = new Token([$token->getId(), $content]);
  70174. }
  70175. }
  70176. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  70177. {
  70178. return new FixerConfigurationResolver([
  70179. (new FixerOptionBuilder('comment_types', 'List of comment types to fix.'))
  70180. ->setAllowedTypes(['string[]'])
  70181. ->setAllowedValues([new AllowedValueSubset(['asterisk', 'hash'])])
  70182. ->setDefault(['asterisk', 'hash'])
  70183. ->getOption(),
  70184. ]);
  70185. }
  70186. }
  70187. <?php
  70188. declare(strict_types=1);
  70189. namespace PhpCsFixer\Fixer\Comment;
  70190. use PhpCsFixer\AbstractFixer;
  70191. use PhpCsFixer\FixerDefinition\CodeSample;
  70192. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70193. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70194. use PhpCsFixer\Preg;
  70195. use PhpCsFixer\Tokenizer\Token;
  70196. use PhpCsFixer\Tokenizer\Tokens;
  70197. final class SingleLineCommentSpacingFixer extends AbstractFixer
  70198. {
  70199. public function getDefinition(): FixerDefinitionInterface
  70200. {
  70201. return new FixerDefinition(
  70202. 'Single-line comments must have proper spacing.',
  70203. [
  70204. new CodeSample(
  70205. '<?php
  70206. //comment 1
  70207. #comment 2
  70208. /*comment 3*/
  70209. '
  70210. ),
  70211. ]
  70212. );
  70213. }
  70214. public function getPriority(): int
  70215. {
  70216. return 1;
  70217. }
  70218. public function isCandidate(Tokens $tokens): bool
  70219. {
  70220. return $tokens->isTokenKindFound(T_COMMENT);
  70221. }
  70222. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70223. {
  70224. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  70225. $token = $tokens[$index];
  70226. if (!$token->isGivenKind(T_COMMENT)) {
  70227. continue;
  70228. }
  70229. $content = $token->getContent();
  70230. $contentLength = \strlen($content);
  70231. if ('/' === $content[0]) {
  70232. if ($contentLength < 3) {
  70233. continue;
  70234. }
  70235. if ('*' === $content[1]) {
  70236. if ($contentLength < 5 || '*' === $content[2] || str_contains($content, "\n")) {
  70237. continue;
  70238. }
  70239. $newContent = rtrim(substr($content, 0, -2)).' '.substr($content, -2);
  70240. $newContent = $this->fixCommentLeadingSpace($newContent, '/*');
  70241. } else {
  70242. $newContent = $this->fixCommentLeadingSpace($content, '//');
  70243. }
  70244. } else {
  70245. if ($contentLength < 2 || '[' === $content[1]) {
  70246. continue;
  70247. }
  70248. $newContent = $this->fixCommentLeadingSpace($content, '#');
  70249. }
  70250. if ($newContent !== $content) {
  70251. $tokens[$index] = new Token([T_COMMENT, $newContent]);
  70252. }
  70253. }
  70254. }
  70255. private function fixCommentLeadingSpace(string $content, string $prefix): string
  70256. {
  70257. if (Preg::match(\sprintf('@^%s\h+.*$@', preg_quote($prefix, '@')), $content)) {
  70258. return $content;
  70259. }
  70260. $position = \strlen($prefix);
  70261. return substr($content, 0, $position).' '.substr($content, $position);
  70262. }
  70263. }
  70264. <?php
  70265. declare(strict_types=1);
  70266. namespace PhpCsFixer\Fixer\Comment;
  70267. use PhpCsFixer\AbstractFixer;
  70268. use PhpCsFixer\FixerDefinition\CodeSample;
  70269. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70270. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70271. use PhpCsFixer\Preg;
  70272. use PhpCsFixer\Tokenizer\Token;
  70273. use PhpCsFixer\Tokenizer\Tokens;
  70274. final class MultilineCommentOpeningClosingFixer extends AbstractFixer
  70275. {
  70276. public function getDefinition(): FixerDefinitionInterface
  70277. {
  70278. return new FixerDefinition(
  70279. 'DocBlocks must start with two asterisks, multiline comments must start with a single asterisk, after the opening slash. Both must end with a single asterisk before the closing slash.',
  70280. [
  70281. new CodeSample(
  70282. <<<'EOT'
  70283. <?php
  70284. /******
  70285. * Multiline comment with arbitrary asterisks count
  70286. ******/
  70287. /**\
  70288. * Multiline comment that seems a DocBlock
  70289. */
  70290. /**
  70291. * DocBlock with arbitrary asterisk count at the end
  70292. **/
  70293. EOT
  70294. ),
  70295. ]
  70296. );
  70297. }
  70298. public function isCandidate(Tokens $tokens): bool
  70299. {
  70300. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT]);
  70301. }
  70302. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70303. {
  70304. foreach ($tokens as $index => $token) {
  70305. $originalContent = $token->getContent();
  70306. if (
  70307. !$token->isGivenKind(T_DOC_COMMENT)
  70308. && !($token->isGivenKind(T_COMMENT) && str_starts_with($originalContent, '/*'))
  70309. ) {
  70310. continue;
  70311. }
  70312. $newContent = $originalContent;
  70313. if ($token->isGivenKind(T_COMMENT)) {
  70314. $newContent = Preg::replace('/^\/\*{2,}(?!\/)/', '/*', $newContent);
  70315. }
  70316. $newContent = Preg::replace('/(?<!\/)\*{2,}\/$/', '*/', $newContent);
  70317. if ($newContent !== $originalContent) {
  70318. $tokens[$index] = new Token([$token->getId(), $newContent]);
  70319. }
  70320. }
  70321. }
  70322. }
  70323. <?php
  70324. declare(strict_types=1);
  70325. namespace PhpCsFixer\Fixer\PhpTag;
  70326. use PhpCsFixer\AbstractFixer;
  70327. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  70328. use PhpCsFixer\FixerDefinition\CodeSample;
  70329. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70330. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70331. use PhpCsFixer\Tokenizer\Token;
  70332. use PhpCsFixer\Tokenizer\Tokens;
  70333. final class LinebreakAfterOpeningTagFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  70334. {
  70335. public function getDefinition(): FixerDefinitionInterface
  70336. {
  70337. return new FixerDefinition(
  70338. 'Ensure there is no code on the same line as the PHP open tag.',
  70339. [new CodeSample("<?php \$a = 1;\n\$b = 3;\n")]
  70340. );
  70341. }
  70342. public function isCandidate(Tokens $tokens): bool
  70343. {
  70344. return $tokens->isMonolithicPhp() && !$tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  70345. }
  70346. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70347. {
  70348. $openTagIndex = $tokens[0]->isGivenKind(T_INLINE_HTML) ? 1 : 0;
  70349. if (str_contains($tokens[$openTagIndex]->getContent(), "\n")) {
  70350. return;
  70351. }
  70352. $newlineFound = false;
  70353. foreach ($tokens as $token) {
  70354. if (($token->isWhitespace() || $token->isGivenKind(T_OPEN_TAG)) && str_contains($token->getContent(), "\n")) {
  70355. $newlineFound = true;
  70356. break;
  70357. }
  70358. }
  70359. if (!$newlineFound) {
  70360. return;
  70361. }
  70362. $tokens[$openTagIndex] = new Token([T_OPEN_TAG, rtrim($tokens[$openTagIndex]->getContent()).$this->whitespacesConfig->getLineEnding()]);
  70363. }
  70364. }
  70365. <?php
  70366. declare(strict_types=1);
  70367. namespace PhpCsFixer\Fixer\PhpTag;
  70368. use PhpCsFixer\AbstractFixer;
  70369. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  70370. use PhpCsFixer\FixerDefinition\CodeSample;
  70371. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70372. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70373. use PhpCsFixer\Tokenizer\Token;
  70374. use PhpCsFixer\Tokenizer\Tokens;
  70375. final class BlankLineAfterOpeningTagFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  70376. {
  70377. public function getDefinition(): FixerDefinitionInterface
  70378. {
  70379. return new FixerDefinition(
  70380. 'Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line.',
  70381. [new CodeSample("<?php \$a = 1;\n\$b = 1;\n")]
  70382. );
  70383. }
  70384. public function getPriority(): int
  70385. {
  70386. return 1;
  70387. }
  70388. public function isCandidate(Tokens $tokens): bool
  70389. {
  70390. return $tokens->isMonolithicPhp() && !$tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  70391. }
  70392. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70393. {
  70394. $lineEnding = $this->whitespacesConfig->getLineEnding();
  70395. $newlineFound = false;
  70396. foreach ($tokens as $token) {
  70397. if (($token->isWhitespace() || $token->isGivenKind(T_OPEN_TAG)) && str_contains($token->getContent(), "\n")) {
  70398. $newlineFound = true;
  70399. break;
  70400. }
  70401. }
  70402. if (!$newlineFound) {
  70403. return;
  70404. }
  70405. $openTagIndex = $tokens[0]->isGivenKind(T_INLINE_HTML) ? 1 : 0;
  70406. $token = $tokens[$openTagIndex];
  70407. if (!str_contains($token->getContent(), "\n")) {
  70408. $tokens[$openTagIndex] = new Token([$token->getId(), rtrim($token->getContent()).$lineEnding]);
  70409. }
  70410. $newLineIndex = $openTagIndex + 1;
  70411. if (!$tokens->offsetExists($newLineIndex)) {
  70412. return;
  70413. }
  70414. if ($tokens[$newLineIndex]->isWhitespace()) {
  70415. if (!str_contains($tokens[$newLineIndex]->getContent(), "\n")) {
  70416. $tokens[$newLineIndex] = new Token([T_WHITESPACE, $lineEnding.$tokens[$newLineIndex]->getContent()]);
  70417. }
  70418. } else {
  70419. $tokens->insertAt($newLineIndex, new Token([T_WHITESPACE, $lineEnding]));
  70420. }
  70421. }
  70422. }
  70423. <?php
  70424. declare(strict_types=1);
  70425. namespace PhpCsFixer\Fixer\PhpTag;
  70426. use PhpCsFixer\AbstractFixer;
  70427. use PhpCsFixer\FixerDefinition\CodeSample;
  70428. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70429. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70430. use PhpCsFixer\Preg;
  70431. use PhpCsFixer\Tokenizer\Token;
  70432. use PhpCsFixer\Tokenizer\Tokens;
  70433. final class FullOpeningTagFixer extends AbstractFixer
  70434. {
  70435. public function getDefinition(): FixerDefinitionInterface
  70436. {
  70437. return new FixerDefinition(
  70438. 'PHP code must use the long `<?php` tags or short-echo `<?=` tags and not other tag variations.',
  70439. [
  70440. new CodeSample(
  70441. '<?
  70442. echo "Hello!";
  70443. '
  70444. ),
  70445. ]
  70446. );
  70447. }
  70448. public function getPriority(): int
  70449. {
  70450. return 98;
  70451. }
  70452. public function isCandidate(Tokens $tokens): bool
  70453. {
  70454. return true;
  70455. }
  70456. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70457. {
  70458. $content = $tokens->generateCode();
  70459. $newContent = Preg::replace('/<\?(?:phP|pHp|pHP|Php|PhP|PHp|PHP)?(\s|$)/', '<?php$1', $content, -1, $count);
  70460. if (0 === $count) {
  70461. return;
  70462. }
  70463. $newTokens = Tokens::fromCode($newContent);
  70464. $tokensOldContentLength = 0;
  70465. foreach ($newTokens as $index => $token) {
  70466. if ($token->isGivenKind(T_OPEN_TAG)) {
  70467. $tokenContent = $token->getContent();
  70468. $possibleOpenContent = substr($content, $tokensOldContentLength, 5);
  70469. if (false === $possibleOpenContent || '<?php' !== strtolower($possibleOpenContent)) { /**
  70470. @phpstan-ignore-line */
  70471. $tokenContent = '<? ';
  70472. }
  70473. $tokensOldContentLength += \strlen($tokenContent);
  70474. continue;
  70475. }
  70476. if ($token->isGivenKind([T_COMMENT, T_DOC_COMMENT, T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_STRING])) {
  70477. $tokenContent = '';
  70478. $tokenContentLength = 0;
  70479. $parts = explode('<?php', $token->getContent());
  70480. $iLast = \count($parts) - 1;
  70481. foreach ($parts as $i => $part) {
  70482. $tokenContent .= $part;
  70483. $tokenContentLength += \strlen($part);
  70484. if ($i !== $iLast) {
  70485. $originalTokenContent = substr($content, $tokensOldContentLength + $tokenContentLength, 5);
  70486. if ('<?php' === strtolower($originalTokenContent)) {
  70487. $tokenContent .= $originalTokenContent;
  70488. $tokenContentLength += 5;
  70489. } else {
  70490. $tokenContent .= '<?';
  70491. $tokenContentLength += 2;
  70492. }
  70493. }
  70494. }
  70495. $newTokens[$index] = new Token([$token->getId(), $tokenContent]);
  70496. $token = $newTokens[$index];
  70497. }
  70498. $tokensOldContentLength += \strlen($token->getContent());
  70499. }
  70500. $tokens->overrideRange(0, $tokens->count() - 1, $newTokens);
  70501. }
  70502. }
  70503. <?php
  70504. declare(strict_types=1);
  70505. namespace PhpCsFixer\Fixer\PhpTag;
  70506. use PhpCsFixer\AbstractFixer;
  70507. use PhpCsFixer\FixerDefinition\CodeSample;
  70508. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70509. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70510. use PhpCsFixer\Tokenizer\Token;
  70511. use PhpCsFixer\Tokenizer\Tokens;
  70512. final class NoClosingTagFixer extends AbstractFixer
  70513. {
  70514. public function getDefinition(): FixerDefinitionInterface
  70515. {
  70516. return new FixerDefinition(
  70517. 'The closing `?>` tag MUST be omitted from files containing only PHP.',
  70518. [new CodeSample("<?php\nclass Sample\n{\n}\n?>\n")]
  70519. );
  70520. }
  70521. public function isCandidate(Tokens $tokens): bool
  70522. {
  70523. return \count($tokens) >= 2 && $tokens->isMonolithicPhp() && $tokens->isTokenKindFound(T_CLOSE_TAG);
  70524. }
  70525. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70526. {
  70527. $closeTags = $tokens->findGivenKind(T_CLOSE_TAG);
  70528. $index = array_key_first($closeTags);
  70529. if (isset($tokens[$index - 1]) && $tokens[$index - 1]->isWhitespace()) {
  70530. $tokens->clearAt($index - 1);
  70531. }
  70532. $tokens->clearAt($index);
  70533. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  70534. if (!$tokens[$prevIndex]->equalsAny([';', '}', [T_OPEN_TAG]])) {
  70535. $tokens->insertAt($prevIndex + 1, new Token(';'));
  70536. }
  70537. }
  70538. }
  70539. <?php
  70540. declare(strict_types=1);
  70541. namespace PhpCsFixer\Fixer\PhpTag;
  70542. use PhpCsFixer\AbstractFixer;
  70543. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  70544. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  70545. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  70546. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  70547. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  70548. use PhpCsFixer\FixerDefinition\CodeSample;
  70549. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70550. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70551. use PhpCsFixer\Tokenizer\Token;
  70552. use PhpCsFixer\Tokenizer\Tokens;
  70553. /**
  70554. @phpstan-type
  70555. @phpstan-type
  70556. @implements
  70557. */
  70558. final class EchoTagSyntaxFixer extends AbstractFixer implements ConfigurableFixerInterface
  70559. {
  70560. /**
  70561. @use */
  70562. use ConfigurableFixerTrait;
  70563. public const OPTION_FORMAT = 'format';
  70564. public const OPTION_SHORTEN_SIMPLE_STATEMENTS_ONLY = 'shorten_simple_statements_only';
  70565. public const OPTION_LONG_FUNCTION = 'long_function';
  70566. public const FORMAT_SHORT = 'short';
  70567. public const FORMAT_LONG = 'long';
  70568. public const LONG_FUNCTION_ECHO = 'echo';
  70569. public const LONG_FUNCTION_PRINT = 'print';
  70570. private const SUPPORTED_FORMAT_OPTIONS = [
  70571. self::FORMAT_LONG,
  70572. self::FORMAT_SHORT,
  70573. ];
  70574. private const SUPPORTED_LONGFUNCTION_OPTIONS = [
  70575. self::LONG_FUNCTION_ECHO,
  70576. self::LONG_FUNCTION_PRINT,
  70577. ];
  70578. public function getDefinition(): FixerDefinitionInterface
  70579. {
  70580. $sample = <<<'EOT'
  70581. <?=1?>
  70582. <?php print '2' . '3'; ?>
  70583. <?php /* comment */ echo '2' . '3'; ?>
  70584. <?php print '2' . '3'; someFunction(); ?>
  70585. EOT;
  70586. return new FixerDefinition(
  70587. 'Replaces short-echo `<?=` with long format `<?php echo`/`<?php print` syntax, or vice-versa.',
  70588. [
  70589. new CodeSample($sample),
  70590. new CodeSample($sample, [self::OPTION_FORMAT => self::FORMAT_LONG]),
  70591. new CodeSample($sample, [self::OPTION_FORMAT => self::FORMAT_LONG, self::OPTION_LONG_FUNCTION => self::LONG_FUNCTION_PRINT]),
  70592. new CodeSample($sample, [self::OPTION_FORMAT => self::FORMAT_SHORT]),
  70593. new CodeSample($sample, [self::OPTION_FORMAT => self::FORMAT_SHORT, self::OPTION_SHORTEN_SIMPLE_STATEMENTS_ONLY => false]),
  70594. ],
  70595. null
  70596. );
  70597. }
  70598. public function getPriority(): int
  70599. {
  70600. return 0;
  70601. }
  70602. public function isCandidate(Tokens $tokens): bool
  70603. {
  70604. if (self::FORMAT_SHORT === $this->configuration[self::OPTION_FORMAT]) {
  70605. return $tokens->isAnyTokenKindsFound([T_ECHO, T_PRINT]);
  70606. }
  70607. return $tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  70608. }
  70609. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  70610. {
  70611. return new FixerConfigurationResolver([
  70612. (new FixerOptionBuilder(self::OPTION_FORMAT, 'The desired language construct.'))
  70613. ->setAllowedValues(self::SUPPORTED_FORMAT_OPTIONS)
  70614. ->setDefault(self::FORMAT_LONG)
  70615. ->getOption(),
  70616. (new FixerOptionBuilder(self::OPTION_LONG_FUNCTION, 'The function to be used to expand the short echo tags.'))
  70617. ->setAllowedValues(self::SUPPORTED_LONGFUNCTION_OPTIONS)
  70618. ->setDefault(self::LONG_FUNCTION_ECHO)
  70619. ->getOption(),
  70620. (new FixerOptionBuilder(self::OPTION_SHORTEN_SIMPLE_STATEMENTS_ONLY, 'Render short-echo tags only in case of simple code.'))
  70621. ->setAllowedTypes(['bool'])
  70622. ->setDefault(true)
  70623. ->getOption(),
  70624. ]);
  70625. }
  70626. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70627. {
  70628. if (self::FORMAT_SHORT === $this->configuration[self::OPTION_FORMAT]) {
  70629. $this->longToShort($tokens);
  70630. } else {
  70631. $this->shortToLong($tokens);
  70632. }
  70633. }
  70634. private function longToShort(Tokens $tokens): void
  70635. {
  70636. $count = $tokens->count();
  70637. for ($index = 0; $index < $count; ++$index) {
  70638. if (!$tokens[$index]->isGivenKind(T_OPEN_TAG)) {
  70639. continue;
  70640. }
  70641. $nextMeaningful = $tokens->getNextMeaningfulToken($index);
  70642. if (null === $nextMeaningful) {
  70643. return;
  70644. }
  70645. if (!$tokens[$nextMeaningful]->isGivenKind([T_ECHO, T_PRINT])) {
  70646. $index = $nextMeaningful;
  70647. continue;
  70648. }
  70649. if (true === $this->configuration[self::OPTION_SHORTEN_SIMPLE_STATEMENTS_ONLY] && $this->isComplexCode($tokens, $nextMeaningful + 1)) {
  70650. $index = $nextMeaningful;
  70651. continue;
  70652. }
  70653. $newTokens = $this->buildLongToShortTokens($tokens, $index, $nextMeaningful);
  70654. $tokens->overrideRange($index, $nextMeaningful, $newTokens);
  70655. $count = $tokens->count();
  70656. }
  70657. }
  70658. private function shortToLong(Tokens $tokens): void
  70659. {
  70660. if (self::LONG_FUNCTION_PRINT === $this->configuration[self::OPTION_LONG_FUNCTION]) {
  70661. $echoToken = [T_PRINT, 'print'];
  70662. } else {
  70663. $echoToken = [T_ECHO, 'echo'];
  70664. }
  70665. $index = -1;
  70666. while (true) {
  70667. $index = $tokens->getNextTokenOfKind($index, [[T_OPEN_TAG_WITH_ECHO]]);
  70668. if (null === $index) {
  70669. return;
  70670. }
  70671. $replace = [new Token([T_OPEN_TAG, '<?php ']), new Token($echoToken)];
  70672. if (!$tokens[$index + 1]->isWhitespace()) {
  70673. $replace[] = new Token([T_WHITESPACE, ' ']);
  70674. }
  70675. $tokens->overrideRange($index, $index, $replace);
  70676. ++$index;
  70677. }
  70678. }
  70679. private function isComplexCode(Tokens $tokens, int $index): bool
  70680. {
  70681. $semicolonFound = false;
  70682. for ($count = $tokens->count(); $index < $count; ++$index) {
  70683. $token = $tokens[$index];
  70684. if ($token->isGivenKind(T_CLOSE_TAG)) {
  70685. return false;
  70686. }
  70687. if (';' === $token->getContent()) {
  70688. $semicolonFound = true;
  70689. } elseif ($semicolonFound && !$token->isWhitespace()) {
  70690. return true;
  70691. }
  70692. }
  70693. return false;
  70694. }
  70695. private function buildLongToShortTokens(Tokens $tokens, int $openTagIndex, int $echoTagIndex): array
  70696. {
  70697. $result = [new Token([T_OPEN_TAG_WITH_ECHO, '<?='])];
  70698. $start = $tokens->getNextNonWhitespace($openTagIndex);
  70699. if ($start === $echoTagIndex) {
  70700. return $result;
  70701. }
  70702. $end = $echoTagIndex - 1;
  70703. while ($tokens[$end]->isWhitespace()) {
  70704. --$end;
  70705. }
  70706. for ($index = $start; $index <= $end; ++$index) {
  70707. $result[] = clone $tokens[$index];
  70708. }
  70709. return $result;
  70710. }
  70711. }
  70712. <?php
  70713. declare(strict_types=1);
  70714. namespace PhpCsFixer\Fixer\ReturnNotation;
  70715. use PhpCsFixer\AbstractFixer;
  70716. use PhpCsFixer\FixerDefinition\CodeSample;
  70717. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70718. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70719. use PhpCsFixer\Tokenizer\CT;
  70720. use PhpCsFixer\Tokenizer\Tokens;
  70721. final class SimplifiedNullReturnFixer extends AbstractFixer
  70722. {
  70723. public function getDefinition(): FixerDefinitionInterface
  70724. {
  70725. return new FixerDefinition(
  70726. 'A return statement wishing to return `void` should not return `null`.',
  70727. [
  70728. new CodeSample("<?php return null;\n"),
  70729. new CodeSample(
  70730. <<<'EOT'
  70731. <?php
  70732. function foo() { return null; }
  70733. function bar(): int { return null; }
  70734. function baz(): ?int { return null; }
  70735. function xyz(): void { return null; }
  70736. EOT
  70737. ),
  70738. ]
  70739. );
  70740. }
  70741. public function getPriority(): int
  70742. {
  70743. return 16;
  70744. }
  70745. public function isCandidate(Tokens $tokens): bool
  70746. {
  70747. return $tokens->isTokenKindFound(T_RETURN);
  70748. }
  70749. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70750. {
  70751. foreach ($tokens as $index => $token) {
  70752. if (!$token->isGivenKind(T_RETURN)) {
  70753. continue;
  70754. }
  70755. if ($this->needFixing($tokens, $index)) {
  70756. $this->clear($tokens, $index);
  70757. }
  70758. }
  70759. }
  70760. private function clear(Tokens $tokens, int $index): void
  70761. {
  70762. while (!$tokens[++$index]->equalsAny([';', [T_CLOSE_TAG]])) {
  70763. if ($this->shouldClearToken($tokens, $index)) {
  70764. $tokens->clearAt($index);
  70765. }
  70766. }
  70767. }
  70768. private function needFixing(Tokens $tokens, int $index): bool
  70769. {
  70770. if ($this->isStrictOrNullableReturnTypeFunction($tokens, $index)) {
  70771. return false;
  70772. }
  70773. $content = '';
  70774. while (!$tokens[$index]->equalsAny([';', [T_CLOSE_TAG]])) {
  70775. $index = $tokens->getNextMeaningfulToken($index);
  70776. $content .= $tokens[$index]->getContent();
  70777. }
  70778. $lastTokenContent = $tokens[$index]->getContent();
  70779. $content = substr($content, 0, -\strlen($lastTokenContent));
  70780. $content = ltrim($content, '(');
  70781. $content = rtrim($content, ')');
  70782. return 'null' === strtolower($content);
  70783. }
  70784. private function isStrictOrNullableReturnTypeFunction(Tokens $tokens, int $returnIndex): bool
  70785. {
  70786. $functionIndex = $returnIndex;
  70787. do {
  70788. $functionIndex = $tokens->getPrevTokenOfKind($functionIndex, [[T_FUNCTION]]);
  70789. if (null === $functionIndex) {
  70790. return false;
  70791. }
  70792. $openingCurlyBraceIndex = $tokens->getNextTokenOfKind($functionIndex, ['{']);
  70793. $closingCurlyBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openingCurlyBraceIndex);
  70794. } while ($closingCurlyBraceIndex < $returnIndex);
  70795. $possibleVoidIndex = $tokens->getPrevMeaningfulToken($openingCurlyBraceIndex);
  70796. $isStrictReturnType = $tokens[$possibleVoidIndex]->isGivenKind([T_STRING, CT::T_ARRAY_TYPEHINT])
  70797. && 'void' !== $tokens[$possibleVoidIndex]->getContent();
  70798. $nullableTypeIndex = $tokens->getNextTokenOfKind($functionIndex, [[CT::T_NULLABLE_TYPE]]);
  70799. $isNullableReturnType = null !== $nullableTypeIndex && $nullableTypeIndex < $openingCurlyBraceIndex;
  70800. return $isStrictReturnType || $isNullableReturnType;
  70801. }
  70802. private function shouldClearToken(Tokens $tokens, int $index): bool
  70803. {
  70804. $token = $tokens[$index];
  70805. if ($token->isComment()) {
  70806. return false;
  70807. }
  70808. if (!$token->isWhitespace()) {
  70809. return true;
  70810. }
  70811. if (
  70812. $tokens[$index + 1]->isComment()
  70813. || $tokens[$index + 1]->equals([T_CLOSE_TAG])
  70814. || ($tokens[$index - 1]->isComment() && $tokens[$index + 1]->equals(';'))
  70815. ) {
  70816. return false;
  70817. }
  70818. return true;
  70819. }
  70820. }
  70821. <?php
  70822. declare(strict_types=1);
  70823. namespace PhpCsFixer\Fixer\ReturnNotation;
  70824. use PhpCsFixer\AbstractFixer;
  70825. use PhpCsFixer\FixerDefinition\CodeSample;
  70826. use PhpCsFixer\FixerDefinition\FixerDefinition;
  70827. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  70828. use PhpCsFixer\Tokenizer\CT;
  70829. use PhpCsFixer\Tokenizer\FCT;
  70830. use PhpCsFixer\Tokenizer\Token;
  70831. use PhpCsFixer\Tokenizer\Tokens;
  70832. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  70833. final class ReturnAssignmentFixer extends AbstractFixer
  70834. {
  70835. private TokensAnalyzer $tokensAnalyzer;
  70836. public function getDefinition(): FixerDefinitionInterface
  70837. {
  70838. return new FixerDefinition(
  70839. 'Local, dynamic and directly referenced variables should not be assigned and directly returned by a function or method.',
  70840. [new CodeSample("<?php\nfunction a() {\n \$a = 1;\n return \$a;\n}\n")]
  70841. );
  70842. }
  70843. public function getPriority(): int
  70844. {
  70845. return -15;
  70846. }
  70847. public function isCandidate(Tokens $tokens): bool
  70848. {
  70849. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN, T_VARIABLE]);
  70850. }
  70851. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  70852. {
  70853. $tokenCount = \count($tokens);
  70854. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  70855. for ($index = 1; $index < $tokenCount; ++$index) {
  70856. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  70857. continue;
  70858. }
  70859. $next = $tokens->getNextMeaningfulToken($index);
  70860. if ($tokens[$next]->isGivenKind(CT::T_RETURN_REF)) {
  70861. continue;
  70862. }
  70863. $functionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  70864. if ($tokens[$functionOpenIndex]->equals(';')) {
  70865. $index = $functionOpenIndex - 1;
  70866. continue;
  70867. }
  70868. $functionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $functionOpenIndex);
  70869. $totalTokensAdded = 0;
  70870. do {
  70871. $tokensAdded = $this->fixFunction(
  70872. $tokens,
  70873. $index,
  70874. $functionOpenIndex,
  70875. $functionCloseIndex
  70876. );
  70877. $functionCloseIndex += $tokensAdded;
  70878. $totalTokensAdded += $tokensAdded;
  70879. } while ($tokensAdded > 0);
  70880. $index = $functionCloseIndex;
  70881. $tokenCount += $totalTokensAdded;
  70882. }
  70883. }
  70884. private function fixFunction(Tokens $tokens, int $functionIndex, int $functionOpenIndex, int $functionCloseIndex): int
  70885. {
  70886. static $riskyKinds = [
  70887. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  70888. T_EVAL,
  70889. T_GLOBAL,
  70890. T_INCLUDE,
  70891. T_INCLUDE_ONCE,
  70892. T_REQUIRE,
  70893. T_REQUIRE_ONCE,
  70894. ];
  70895. $inserted = 0;
  70896. $candidates = [];
  70897. $isRisky = false;
  70898. if ($tokens[$tokens->getNextMeaningfulToken($functionIndex)]->isGivenKind(CT::T_RETURN_REF)) {
  70899. $isRisky = true;
  70900. }
  70901. for ($index = $functionIndex + 1; $index < $functionOpenIndex; ++$index) {
  70902. if ($tokens[$index]->equals('&')) {
  70903. $isRisky = true;
  70904. break;
  70905. }
  70906. }
  70907. for ($index = $functionOpenIndex + 1; $index < $functionCloseIndex; ++$index) {
  70908. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  70909. $nestedFunctionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  70910. if ($tokens[$nestedFunctionOpenIndex]->equals(';')) {
  70911. $index = $nestedFunctionOpenIndex - 1;
  70912. continue;
  70913. }
  70914. $nestedFunctionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nestedFunctionOpenIndex);
  70915. $tokensAdded = $this->fixFunction(
  70916. $tokens,
  70917. $index,
  70918. $nestedFunctionOpenIndex,
  70919. $nestedFunctionCloseIndex
  70920. );
  70921. $index = $nestedFunctionCloseIndex + $tokensAdded;
  70922. $functionCloseIndex += $tokensAdded;
  70923. $inserted += $tokensAdded;
  70924. }
  70925. if ($isRisky) {
  70926. continue;
  70927. }
  70928. if ($tokens[$index]->equals('&')) {
  70929. $isRisky = true;
  70930. continue;
  70931. }
  70932. if ($tokens[$index]->isGivenKind(T_RETURN)) {
  70933. $candidates[] = $index;
  70934. continue;
  70935. }
  70936. if ($tokens[$index]->isGivenKind($riskyKinds)) {
  70937. $isRisky = true;
  70938. continue;
  70939. }
  70940. if ($tokens[$index]->isGivenKind(T_STATIC)) {
  70941. $nextIndex = $tokens->getNextMeaningfulToken($index);
  70942. if (!$tokens[$nextIndex]->isGivenKind(T_FUNCTION)) {
  70943. $isRisky = true;
  70944. continue;
  70945. }
  70946. }
  70947. if ($tokens[$index]->equals('$')) {
  70948. $nextIndex = $tokens->getNextMeaningfulToken($index);
  70949. if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
  70950. $isRisky = true;
  70951. continue;
  70952. }
  70953. }
  70954. if ($this->tokensAnalyzer->isSuperGlobal($index)) {
  70955. $isRisky = true;
  70956. continue;
  70957. }
  70958. }
  70959. if ($isRisky) {
  70960. return $inserted;
  70961. }
  70962. for ($i = \count($candidates) - 1; $i >= 0; --$i) {
  70963. $index = $candidates[$i];
  70964. $returnVarIndex = $tokens->getNextMeaningfulToken($index);
  70965. if (!$tokens[$returnVarIndex]->isGivenKind(T_VARIABLE)) {
  70966. continue;
  70967. }
  70968. $endReturnVarIndex = $tokens->getNextMeaningfulToken($returnVarIndex);
  70969. if (!$tokens[$endReturnVarIndex]->equalsAny([';', [T_CLOSE_TAG]])) {
  70970. continue;
  70971. }
  70972. $assignVarEndIndex = $tokens->getPrevMeaningfulToken($index);
  70973. if (!$tokens[$assignVarEndIndex]->equals(';')) {
  70974. continue;
  70975. }
  70976. while (true) {
  70977. $prevMeaningFul = $tokens->getPrevMeaningfulToken($assignVarEndIndex);
  70978. if (!$tokens[$prevMeaningFul]->equals(')')) {
  70979. break;
  70980. }
  70981. $assignVarEndIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevMeaningFul);
  70982. }
  70983. $assignVarOperatorIndex = $tokens->getPrevTokenOfKind(
  70984. $assignVarEndIndex,
  70985. ['=', ';', '{', '}', [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]
  70986. );
  70987. if ($tokens[$assignVarOperatorIndex]->equals('}')) {
  70988. $startIndex = $this->isCloseBracePartOfDefinition($tokens, $assignVarOperatorIndex);
  70989. if (null === $startIndex) {
  70990. continue;
  70991. }
  70992. $assignVarOperatorIndex = $tokens->getPrevMeaningfulToken($startIndex);
  70993. }
  70994. if (!$tokens[$assignVarOperatorIndex]->equals('=')) {
  70995. continue;
  70996. }
  70997. $assignVarIndex = $tokens->getPrevMeaningfulToken($assignVarOperatorIndex);
  70998. if (!$tokens[$assignVarIndex]->equals($tokens[$returnVarIndex], false)) {
  70999. continue;
  71000. }
  71001. $beforeAssignVarIndex = $tokens->getPrevMeaningfulToken($assignVarIndex);
  71002. if (!$tokens[$beforeAssignVarIndex]->equalsAny([';', '{', '}'])) {
  71003. continue;
  71004. }
  71005. if ($this->isUsedInCatchOrFinally($tokens, $returnVarIndex, $functionOpenIndex, $functionCloseIndex)) {
  71006. continue;
  71007. }
  71008. $inserted += $this->simplifyReturnStatement(
  71009. $tokens,
  71010. $assignVarIndex,
  71011. $assignVarOperatorIndex,
  71012. $index,
  71013. $endReturnVarIndex
  71014. );
  71015. }
  71016. return $inserted;
  71017. }
  71018. private function simplifyReturnStatement(
  71019. Tokens $tokens,
  71020. int $assignVarIndex,
  71021. int $assignVarOperatorIndex,
  71022. int $returnIndex,
  71023. int $returnVarEndIndex
  71024. ): int {
  71025. $inserted = 0;
  71026. $originalIndent = $tokens[$assignVarIndex - 1]->isWhitespace()
  71027. ? $tokens[$assignVarIndex - 1]->getContent()
  71028. : null;
  71029. if ($tokens[$returnVarEndIndex]->equals(';')) {
  71030. $tokens->clearTokenAndMergeSurroundingWhitespace($returnVarEndIndex);
  71031. }
  71032. for ($i = $returnIndex; $i <= $returnVarEndIndex - 1; ++$i) {
  71033. $this->clearIfSave($tokens, $i);
  71034. }
  71035. if ($tokens[$returnIndex - 1]->isWhitespace()) {
  71036. $content = $tokens[$returnIndex - 1]->getContent();
  71037. $fistLinebreakPos = strrpos($content, "\n");
  71038. $content = false === $fistLinebreakPos
  71039. ? ' '
  71040. : substr($content, $fistLinebreakPos);
  71041. $tokens[$returnIndex - 1] = new Token([T_WHITESPACE, $content]);
  71042. }
  71043. for ($i = $assignVarIndex; $i <= $assignVarOperatorIndex; ++$i) {
  71044. $this->clearIfSave($tokens, $i);
  71045. }
  71046. $tokens->insertAt($assignVarIndex, new Token([T_RETURN, 'return']));
  71047. ++$inserted;
  71048. if (
  71049. null !== $originalIndent
  71050. && $tokens[$assignVarIndex - 1]->isWhitespace()
  71051. && $originalIndent !== $tokens[$assignVarIndex - 1]->getContent()
  71052. ) {
  71053. $tokens[$assignVarIndex - 1] = new Token([T_WHITESPACE, $originalIndent]);
  71054. }
  71055. $nextIndex = $tokens->getNonEmptySibling($assignVarIndex, 1);
  71056. if (!$tokens[$nextIndex]->isWhitespace()) {
  71057. $tokens->insertAt($nextIndex, new Token([T_WHITESPACE, ' ']));
  71058. ++$inserted;
  71059. }
  71060. return $inserted;
  71061. }
  71062. private function clearIfSave(Tokens $tokens, int $index): void
  71063. {
  71064. if ($tokens[$index]->isComment()) {
  71065. return;
  71066. }
  71067. if ($tokens[$index]->isWhitespace() && $tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  71068. return;
  71069. }
  71070. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  71071. }
  71072. private function isCloseBracePartOfDefinition(Tokens $tokens, int $index): ?int
  71073. {
  71074. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  71075. $candidateIndex = $this->isOpenBraceOfLambda($tokens, $index);
  71076. if (null !== $candidateIndex) {
  71077. return $candidateIndex;
  71078. }
  71079. $candidateIndex = $this->isOpenBraceOfAnonymousClass($tokens, $index);
  71080. return $candidateIndex ?? $this->isOpenBraceOfMatch($tokens, $index);
  71081. }
  71082. private function isOpenBraceOfAnonymousClass(Tokens $tokens, int $index): ?int
  71083. {
  71084. do {
  71085. $index = $tokens->getPrevMeaningfulToken($index);
  71086. } while ($tokens[$index]->equalsAny([',', [T_STRING], [T_IMPLEMENTS], [T_EXTENDS], [T_NS_SEPARATOR]]));
  71087. if ($tokens[$index]->equals(')')) {
  71088. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  71089. $index = $tokens->getPrevMeaningfulToken($index);
  71090. }
  71091. if (!$tokens[$index]->isGivenKind(T_CLASS) || !$this->tokensAnalyzer->isAnonymousClass($index)) {
  71092. return null;
  71093. }
  71094. return $tokens->getPrevTokenOfKind($index, [[T_NEW]]);
  71095. }
  71096. private function isOpenBraceOfLambda(Tokens $tokens, int $index): ?int
  71097. {
  71098. $index = $tokens->getPrevMeaningfulToken($index);
  71099. if (!$tokens[$index]->equals(')')) {
  71100. return null;
  71101. }
  71102. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  71103. $index = $tokens->getPrevMeaningfulToken($index);
  71104. if ($tokens[$index]->isGivenKind(CT::T_USE_LAMBDA)) {
  71105. $index = $tokens->getPrevTokenOfKind($index, [')']);
  71106. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  71107. $index = $tokens->getPrevMeaningfulToken($index);
  71108. }
  71109. if ($tokens[$index]->isGivenKind(CT::T_RETURN_REF)) {
  71110. $index = $tokens->getPrevMeaningfulToken($index);
  71111. }
  71112. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  71113. return null;
  71114. }
  71115. $staticCandidate = $tokens->getPrevMeaningfulToken($index);
  71116. return $tokens[$staticCandidate]->isGivenKind(T_STATIC) ? $staticCandidate : $index;
  71117. }
  71118. private function isOpenBraceOfMatch(Tokens $tokens, int $index): ?int
  71119. {
  71120. if (!$tokens->isTokenKindFound(FCT::T_MATCH)) {
  71121. return null;
  71122. }
  71123. $index = $tokens->getPrevMeaningfulToken($index);
  71124. if (!$tokens[$index]->equals(')')) {
  71125. return null;
  71126. }
  71127. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  71128. $index = $tokens->getPrevMeaningfulToken($index);
  71129. return $tokens[$index]->isGivenKind(T_MATCH) ? $index : null;
  71130. }
  71131. private function isUsedInCatchOrFinally(Tokens $tokens, int $returnVarIndex, int $functionOpenIndex, int $functionCloseIndex): bool
  71132. {
  71133. $tryIndex = $tokens->getPrevTokenOfKind($returnVarIndex, [[T_TRY]]);
  71134. if (null === $tryIndex || $tryIndex <= $functionOpenIndex) {
  71135. return false;
  71136. }
  71137. $tryOpenIndex = $tokens->getNextTokenOfKind($tryIndex, ['{']);
  71138. $tryCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $tryOpenIndex);
  71139. $nextIndex = $tokens->getNextMeaningfulToken($tryCloseIndex);
  71140. if (null === $nextIndex) {
  71141. return false;
  71142. }
  71143. while ($tokens[$nextIndex]->isGivenKind(T_CATCH)) {
  71144. $catchOpenIndex = $tokens->getNextTokenOfKind($nextIndex, ['{']);
  71145. $catchCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $catchOpenIndex);
  71146. if ($catchCloseIndex >= $functionCloseIndex) {
  71147. return false;
  71148. }
  71149. $varIndex = $tokens->getNextTokenOfKind($catchOpenIndex, [$tokens[$returnVarIndex]]);
  71150. if (null !== $varIndex && $varIndex < $catchCloseIndex) {
  71151. return true;
  71152. }
  71153. $nextIndex = $tokens->getNextMeaningfulToken($catchCloseIndex);
  71154. if (null === $nextIndex) {
  71155. return false;
  71156. }
  71157. }
  71158. if (!$tokens[$nextIndex]->isGivenKind(T_FINALLY)) {
  71159. return false;
  71160. }
  71161. $finallyIndex = $nextIndex;
  71162. if ($finallyIndex >= $functionCloseIndex) {
  71163. return false;
  71164. }
  71165. $finallyOpenIndex = $tokens->getNextTokenOfKind($finallyIndex, ['{']);
  71166. $finallyCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $finallyOpenIndex);
  71167. $varIndex = $tokens->getNextTokenOfKind($finallyOpenIndex, [$tokens[$returnVarIndex]]);
  71168. if (null !== $varIndex && $varIndex < $finallyCloseIndex) {
  71169. return true;
  71170. }
  71171. return false;
  71172. }
  71173. }
  71174. <?php
  71175. declare(strict_types=1);
  71176. namespace PhpCsFixer\Fixer\ReturnNotation;
  71177. use PhpCsFixer\AbstractFixer;
  71178. use PhpCsFixer\FixerDefinition\CodeSample;
  71179. use PhpCsFixer\FixerDefinition\FixerDefinition;
  71180. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  71181. use PhpCsFixer\Tokenizer\Tokens;
  71182. final class NoUselessReturnFixer extends AbstractFixer
  71183. {
  71184. public function isCandidate(Tokens $tokens): bool
  71185. {
  71186. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN]);
  71187. }
  71188. public function getDefinition(): FixerDefinitionInterface
  71189. {
  71190. return new FixerDefinition(
  71191. 'There should not be an empty `return` statement at the end of a function.',
  71192. [
  71193. new CodeSample(
  71194. '<?php
  71195. function example($b) {
  71196. if ($b) {
  71197. return;
  71198. }
  71199. return;
  71200. }
  71201. '
  71202. ),
  71203. ]
  71204. );
  71205. }
  71206. public function getPriority(): int
  71207. {
  71208. return -18;
  71209. }
  71210. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71211. {
  71212. foreach ($tokens as $index => $token) {
  71213. if (!$token->isGivenKind(T_FUNCTION)) {
  71214. continue;
  71215. }
  71216. $index = $tokens->getNextTokenOfKind($index, [';', '{']);
  71217. if ($tokens[$index]->equals('{')) {
  71218. $this->fixFunction($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
  71219. }
  71220. }
  71221. }
  71222. private function fixFunction(Tokens $tokens, int $start, int $end): void
  71223. {
  71224. for ($index = $end; $index > $start; --$index) {
  71225. if (!$tokens[$index]->isGivenKind(T_RETURN)) {
  71226. continue;
  71227. }
  71228. $nextAt = $tokens->getNextMeaningfulToken($index);
  71229. if (!$tokens[$nextAt]->equals(';')) {
  71230. continue;
  71231. }
  71232. if ($tokens->getNextMeaningfulToken($nextAt) !== $end) {
  71233. continue;
  71234. }
  71235. $previous = $tokens->getPrevMeaningfulToken($index);
  71236. if ($tokens[$previous]->equalsAny([[T_ELSE], ')'])) {
  71237. continue;
  71238. }
  71239. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  71240. $tokens->clearTokenAndMergeSurroundingWhitespace($nextAt);
  71241. }
  71242. }
  71243. }
  71244. <?php
  71245. declare(strict_types=1);
  71246. namespace PhpCsFixer\Fixer;
  71247. use PhpCsFixer\AbstractFixer;
  71248. use PhpCsFixer\Tokenizer\Tokens;
  71249. abstract class AbstractIncrementOperatorFixer extends AbstractFixer
  71250. {
  71251. final protected function findStart(Tokens $tokens, int $index): int
  71252. {
  71253. do {
  71254. $index = $tokens->getPrevMeaningfulToken($index);
  71255. $token = $tokens[$index];
  71256. $blockType = Tokens::detectBlockType($token);
  71257. if (null !== $blockType && !$blockType['isStart']) {
  71258. $index = $tokens->findBlockStart($blockType['type'], $index);
  71259. $token = $tokens[$index];
  71260. }
  71261. } while (!$token->equalsAny(['$', [T_VARIABLE]]));
  71262. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  71263. $prevToken = $tokens[$prevIndex];
  71264. if ($prevToken->equals('$')) {
  71265. return $this->findStart($tokens, $index);
  71266. }
  71267. if ($prevToken->isObjectOperator()) {
  71268. return $this->findStart($tokens, $prevIndex);
  71269. }
  71270. if ($prevToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  71271. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  71272. if (!$tokens[$prevPrevIndex]->isGivenKind([T_STATIC, T_STRING])) {
  71273. return $this->findStart($tokens, $prevIndex);
  71274. }
  71275. $index = $tokens->getTokenNotOfKindsSibling($prevIndex, -1, [T_NS_SEPARATOR, T_STATIC, T_STRING]);
  71276. $index = $tokens->getNextMeaningfulToken($index);
  71277. }
  71278. return $index;
  71279. }
  71280. }
  71281. <?php
  71282. declare(strict_types=1);
  71283. namespace PhpCsFixer\Fixer;
  71284. interface DeprecatedFixerInterface extends FixerInterface
  71285. {
  71286. public function getSuccessorsNames(): array;
  71287. }
  71288. <?php
  71289. declare(strict_types=1);
  71290. namespace PhpCsFixer\Fixer\Internal;
  71291. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  71292. use PhpCsFixer\AbstractFixer;
  71293. use PhpCsFixer\AbstractPhpdocToTypeDeclarationFixer;
  71294. use PhpCsFixer\Console\Command\HelpCommand;
  71295. use PhpCsFixer\DocBlock\DocBlock;
  71296. use PhpCsFixer\Doctrine\Annotation\Tokens as DoctrineAnnotationTokens;
  71297. use PhpCsFixer\Fixer\AttributeNotation\OrderedAttributesFixer;
  71298. use PhpCsFixer\Fixer\Casing\ConstantCaseFixer;
  71299. use PhpCsFixer\Fixer\ClassNotation\FinalInternalClassFixer;
  71300. use PhpCsFixer\Fixer\Comment\HeaderCommentFixer;
  71301. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  71302. use PhpCsFixer\Fixer\ControlStructure\NoBreakCommentFixer;
  71303. use PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer;
  71304. use PhpCsFixer\Fixer\FixerInterface;
  71305. use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
  71306. use PhpCsFixer\Fixer\InternalFixerInterface;
  71307. use PhpCsFixer\Fixer\NamespaceNotation\BlankLinesBeforeNamespaceFixer;
  71308. use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
  71309. use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocTagRenameFixer;
  71310. use PhpCsFixer\Fixer\Phpdoc\PhpdocOrderByValueFixer;
  71311. use PhpCsFixer\Fixer\Phpdoc\PhpdocReturnSelfReferenceFixer;
  71312. use PhpCsFixer\Fixer\Phpdoc\PhpdocTagTypeFixer;
  71313. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  71314. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  71315. use PhpCsFixer\FixerDefinition\CodeSample;
  71316. use PhpCsFixer\FixerDefinition\FixerDefinition;
  71317. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  71318. use PhpCsFixer\Preg;
  71319. use PhpCsFixer\StdinFileInfo;
  71320. use PhpCsFixer\Tests\AbstractDoctrineAnnotationFixerTestCase;
  71321. use PhpCsFixer\Tests\AbstractFixerTest;
  71322. use PhpCsFixer\Tests\AbstractFunctionReferenceFixerTest;
  71323. use PhpCsFixer\Tests\AbstractProxyFixerTest;
  71324. use PhpCsFixer\Tests\Fixer\Whitespace\AbstractNullableTypeDeclarationFixerTestCase;
  71325. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  71326. use PhpCsFixer\Tokenizer\CT;
  71327. use PhpCsFixer\Tokenizer\FCT;
  71328. use PhpCsFixer\Tokenizer\Token;
  71329. use PhpCsFixer\Tokenizer\Tokens;
  71330. use PhpCsFixer\Utils;
  71331. /**
  71332. @warning
  71333. */
  71334. final class ConfigurableFixerTemplateFixer extends AbstractFixer implements InternalFixerInterface
  71335. {
  71336. private const MODIFIERS = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT, FCT::T_ATTRIBUTE, FCT::T_READONLY];
  71337. public function getName(): string
  71338. {
  71339. return 'PhpCsFixerInternal/'.parent::getName();
  71340. }
  71341. public function getDefinition(): FixerDefinitionInterface
  71342. {
  71343. $fileInfo = $this->getExampleFixerFile();
  71344. $file = $fileInfo->openFile('r');
  71345. $content = $file->fread($file->getSize());
  71346. if (false === $content) {
  71347. throw new \RuntimeException('Cannot read example file.');
  71348. }
  71349. $tokens = Tokens::fromCode($content);
  71350. $generalPhpdocAnnotationRemoveFixer = new GeneralPhpdocAnnotationRemoveFixer();
  71351. $generalPhpdocAnnotationRemoveFixer->configure([
  71352. 'annotations' => [
  71353. 'implements',
  71354. 'phpstan-type',
  71355. ],
  71356. ]);
  71357. $generalPhpdocAnnotationRemoveFixer->applyFix($fileInfo, $tokens);
  71358. return new FixerDefinition(
  71359. 'Configurable Fixers must declare Template type.',
  71360. [
  71361. new CodeSample(
  71362. $tokens->generateCode()
  71363. ),
  71364. ],
  71365. null,
  71366. 'This rule auto-adjust @implements and @phpstan-type, which heavily change information for SCA.'
  71367. );
  71368. }
  71369. public function isCandidate(Tokens $tokens): bool
  71370. {
  71371. return $tokens->isTokenKindFound(T_CLASS);
  71372. }
  71373. public function isRisky(): bool
  71374. {
  71375. return true;
  71376. }
  71377. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71378. {
  71379. $this->applyFixForSrc($file, $tokens);
  71380. $this->applyFixForTest($file, $tokens);
  71381. }
  71382. private function applyFixForTest(\SplFileInfo $file, Tokens $tokens): void
  71383. {
  71384. if (!$this->isTestForFixerFile($file)) {
  71385. return;
  71386. }
  71387. $classIndex = $tokens->getNextTokenOfKind(0, [[T_CLASS]]);
  71388. $docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
  71389. if (!$this->isPHPDoc($tokens, $docBlockIndex)) {
  71390. $docBlockIndex = $tokens->getNextMeaningfulToken($docBlockIndex);
  71391. $tokens->insertAt($docBlockIndex, [
  71392. new Token([T_DOC_COMMENT, "/**\n */"]),
  71393. new Token([T_WHITESPACE, "\n"]),
  71394. ]);
  71395. }
  71396. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  71397. if (!$doc->isMultiLine()) {
  71398. throw new \RuntimeException('Non-multiline docblock not expected, please convert it manually!');
  71399. }
  71400. $covers = array_map(
  71401. static function ($annotation): string {
  71402. $parts = explode(' ', $annotation->getContent());
  71403. return trim(array_pop($parts));
  71404. },
  71405. $doc->getAnnotationsOfType(['covers'])
  71406. );
  71407. $covers = array_filter(
  71408. $covers,
  71409. static fn ($className): bool => !str_contains($className, '\Abstract') && str_ends_with($className, 'Fixer')
  71410. );
  71411. if (1 !== \count($covers)) {
  71412. throw new \RuntimeException('Non-single covers annotation, please handle manually!');
  71413. }
  71414. $fixerName = array_pop($covers);
  71415. $allowedBaseClasses = [
  71416. AbstractDoctrineAnnotationFixerTestCase::class,
  71417. AbstractNullableTypeDeclarationFixerTestCase::class,
  71418. AbstractFixerTestCase::class,
  71419. ];
  71420. $currentClassName = str_replace('\PhpCsFixer', '\PhpCsFixer\Tests', $fixerName).'Test';
  71421. $baseClassName = false;
  71422. while (true) {
  71423. $baseClassName = get_parent_class($currentClassName);
  71424. if (false === $baseClassName || \in_array($baseClassName, $allowedBaseClasses, true)) {
  71425. break;
  71426. }
  71427. $currentClassName = $baseClassName;
  71428. }
  71429. if (false === $baseClassName) {
  71430. throw new \RuntimeException('Cannot find valid parent class!');
  71431. }
  71432. $baseClassName = self::getShortClassName($baseClassName);
  71433. $expectedAnnotation = \sprintf('extends %s<%s>', $baseClassName, $fixerName);
  71434. $expectedAnnotationPresent = false;
  71435. $expectedTypeImport = \sprintf('phpstan-import-type _AutogeneratedInputConfiguration from %s', $fixerName);
  71436. $expectedTypeImportPresent = false;
  71437. foreach ($doc->getAnnotationsOfType(['extends']) as $annotation) {
  71438. $annotationContent = $annotation->getContent();
  71439. Preg::match('#^.*?(?P<annotation>@extends\s+?(?P<class>\w+)\<[^>]+?\>\S*)\s*?$#s', $annotationContent, $matches);
  71440. if (
  71441. ($matches['class'] ?? '') === $baseClassName
  71442. ) {
  71443. if (($matches['annotation'] ?? '') !== '@'.$expectedAnnotation) {
  71444. $annotationStart = $annotation->getStart();
  71445. $annotation->remove();
  71446. $doc->getLine($annotationStart)->setContent(' * @'.$expectedAnnotation."\n");
  71447. }
  71448. $expectedAnnotationPresent = true;
  71449. break;
  71450. }
  71451. }
  71452. $implements = class_implements($fixerName);
  71453. if (isset($implements[ConfigurableFixerInterface::class])) {
  71454. foreach ($doc->getAnnotationsOfType(['phpstan-import-type']) as $annotation) {
  71455. $annotationContent = $annotation->getContent();
  71456. Preg::match('#^.*?(@'.preg_quote($expectedTypeImport, '\\').')\s*?$#s', $annotationContent, $matches);
  71457. if ([] !== $matches) {
  71458. $expectedTypeImportPresent = true;
  71459. }
  71460. }
  71461. } else {
  71462. $expectedTypeImportPresent = true;
  71463. }
  71464. if (!$expectedAnnotationPresent || !$expectedTypeImportPresent) {
  71465. $lines = $doc->getLines();
  71466. $lastLine = end($lines);
  71467. \assert(false !== $lastLine);
  71468. $lastLine->setContent(
  71469. ''
  71470. .(!$expectedAnnotationPresent ? ' * @'.$expectedAnnotation."\n" : '')
  71471. .(!$expectedTypeImportPresent ? ' * @'.$expectedTypeImport."\n" : '')
  71472. .$lastLine->getContent()
  71473. );
  71474. }
  71475. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  71476. }
  71477. private function applyFixForSrc(\SplFileInfo $file, Tokens $tokens): void
  71478. {
  71479. if ($file instanceof StdinFileInfo) {
  71480. $file = $this->getExampleFixerFile();
  71481. }
  71482. $fixer = $this->getFixerForSrcFile($file);
  71483. if (null === $fixer || !$fixer instanceof ConfigurableFixerInterface) {
  71484. return;
  71485. }
  71486. $optionTypeInput = [];
  71487. $optionTypeComputed = [];
  71488. $configurationDefinition = $fixer->getConfigurationDefinition();
  71489. foreach ($configurationDefinition->getOptions() as $option) {
  71490. $optionName = $option->getName();
  71491. $allowed = HelpCommand::getDisplayableAllowedValues($option);
  71492. $allowedAfterNormalization = null;
  71493. if (null !== $option->getNormalizer()) {
  71494. if ($fixer instanceof PhpdocOrderByValueFixer && 'annotations' === $optionName) {
  71495. $allowedAfterNormalization = 'array{'
  71496. .implode(
  71497. ', ',
  71498. array_map(
  71499. static fn ($value): string => \sprintf("'%s'?: '%s'", $value, strtolower($value)),
  71500. $allowed[0]->getAllowedValues()
  71501. )
  71502. )
  71503. .'}';
  71504. } elseif ($fixer instanceof HeaderCommentFixer && \in_array($optionName, ['header', 'validator'], true)) {
  71505. } elseif ($fixer instanceof BlankLinesBeforeNamespaceFixer && \in_array($optionName, ['min_line_breaks', 'max_line_breaks'], true)) {
  71506. } elseif ($fixer instanceof PhpdocReturnSelfReferenceFixer && 'replacements' === $optionName) {
  71507. } elseif ($fixer instanceof GeneralPhpdocTagRenameFixer && 'replacements' === $optionName) {
  71508. } elseif ($fixer instanceof NoBreakCommentFixer && 'comment_text' === $optionName) {
  71509. } elseif ($fixer instanceof TrailingCommaInMultilineFixer && 'elements' === $optionName) {
  71510. } elseif ($fixer instanceof OrderedAttributesFixer && 'sort_algorithm' === $optionName) {
  71511. } elseif ($fixer instanceof OrderedAttributesFixer && 'order' === $optionName) {
  71512. $allowedAfterNormalization = 'array<string, int>';
  71513. } elseif ($fixer instanceof FinalInternalClassFixer && \in_array($optionName, ['annotation_include', 'annotation_exclude', 'include', 'exclude'], true)) {
  71514. $allowedAfterNormalization = 'array<string, string>';
  71515. } elseif ($fixer instanceof PhpdocTagTypeFixer && 'tags' === $optionName) {
  71516. } elseif ($fixer instanceof OrderedImportsFixer && 'sort_algorithm' === $optionName) {
  71517. } else {
  71518. throw new \LogicException(\sprintf('How to handle normalized types of "%s.%s"? Explicit instructions needed!', $fixer->getName(), $optionName));
  71519. }
  71520. }
  71521. if (\is_array($allowed)) {
  71522. $allowed = array_map(
  71523. static fn ($value): string => $value instanceof AllowedValueSubset
  71524. ? \sprintf('list<%s>', implode('|', array_map(static fn ($val) => "'".$val."'", $value->getAllowedValues())))
  71525. : Utils::toString($value),
  71526. $allowed
  71527. );
  71528. } else {
  71529. $allowed = array_map(
  71530. static fn ($value): string => Utils::convertArrayTypeToList($value),
  71531. $option->getAllowedTypes()
  71532. );
  71533. }
  71534. sort($allowed);
  71535. $allowed = implode('|', $allowed);
  71536. if ('array' === $allowed) {
  71537. $default = $option->getDefault();
  71538. $getTypes = static fn ($values): array => array_unique(array_map(
  71539. static fn ($val) => \gettype($val),
  71540. $values
  71541. ));
  71542. $defaultKeyTypes = $getTypes(array_keys($default));
  71543. $defaultValueTypes = $getTypes(array_values($default));
  71544. $allowed = \sprintf(
  71545. 'array<%s, %s>',
  71546. [] !== $defaultKeyTypes ? implode('|', $defaultKeyTypes) : 'array-key',
  71547. [] !== $defaultValueTypes ? implode('|', $defaultValueTypes) : 'mixed'
  71548. );
  71549. }
  71550. $optionTypeInput[] = \sprintf('%s%s: %s', $optionName, $option->hasDefault() ? '?' : '', $allowed);
  71551. $optionTypeComputed[] = \sprintf('%s: %s', $optionName, $allowedAfterNormalization ?? $allowed);
  71552. }
  71553. $expectedTemplateTypeInputAnnotation = \sprintf("phpstan-type _AutogeneratedInputConfiguration array{\n * %s,\n * }", implode(",\n * ", $optionTypeInput));
  71554. $expectedTemplateTypeComputedAnnotation = \sprintf("phpstan-type _AutogeneratedComputedConfiguration array{\n * %s,\n * }", implode(",\n * ", $optionTypeComputed));
  71555. $expectedImplementsWithTypesAnnotation = 'implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>';
  71556. $classIndex = $tokens->getNextTokenOfKind(0, [[T_CLASS]]);
  71557. $docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
  71558. if (!$this->isPHPDoc($tokens, $docBlockIndex)) {
  71559. $docBlockIndex = $tokens->getNextMeaningfulToken($docBlockIndex);
  71560. $tokens->insertAt($docBlockIndex, [
  71561. new Token([T_DOC_COMMENT, "/**\n */"]),
  71562. new Token([T_WHITESPACE, "\n"]),
  71563. ]);
  71564. }
  71565. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  71566. if (!$doc->isMultiLine()) {
  71567. throw new \RuntimeException('Non-multiline docblock not expected, please convert it manually!');
  71568. }
  71569. $templateTypeInputPresent = false;
  71570. $templateTypeComputedPresent = false;
  71571. $implementsWithTypesPresent = false;
  71572. foreach ($doc->getAnnotationsOfType(['phpstan-type']) as $annotation) {
  71573. $annotationContent = $annotation->getContent();
  71574. $matches = [];
  71575. Preg::match('#^.*?(?P<annotation>@phpstan-type\s+?(?P<typeName>.+?)\s+?(?P<typeContent>.+?))\s*?$#s', $annotationContent, $matches);
  71576. if (
  71577. ($matches['typeName'] ?? '') === '_AutogeneratedInputConfiguration'
  71578. ) {
  71579. if (($matches['annotation'] ?? '') !== '@'.$expectedTemplateTypeInputAnnotation) {
  71580. $annotationStart = $annotation->getStart();
  71581. $annotation->remove();
  71582. $doc->getLine($annotationStart)->setContent(' * @'.$expectedTemplateTypeInputAnnotation."\n");
  71583. }
  71584. $templateTypeInputPresent = true;
  71585. continue;
  71586. }
  71587. if (
  71588. ($matches['typeName'] ?? '') === '_AutogeneratedComputedConfiguration'
  71589. ) {
  71590. if (($matches['annotation'] ?? '') !== '@'.$expectedTemplateTypeComputedAnnotation) {
  71591. $annotationStart = $annotation->getStart();
  71592. $annotation->remove();
  71593. $doc->getLine($annotationStart)->setContent(' * @'.$expectedTemplateTypeComputedAnnotation."\n");
  71594. }
  71595. $templateTypeComputedPresent = true;
  71596. continue;
  71597. }
  71598. }
  71599. foreach ($doc->getAnnotationsOfType(['implements']) as $annotation) {
  71600. $annotationContent = $annotation->getContent();
  71601. Preg::match('#^.*?(?P<annotation>@implements\s+?(?P<class>\w+)\<[^>]+?\>\S*)\s*?$#s', $annotationContent, $matches);
  71602. if (
  71603. ($matches['class'] ?? '') === 'ConfigurableFixerInterface'
  71604. ) {
  71605. if (($matches['annotation'] ?? '') !== '@'.$expectedImplementsWithTypesAnnotation) {
  71606. $annotationStart = $annotation->getStart();
  71607. $annotation->remove();
  71608. $doc->getLine($annotationStart)->setContent(' * @'.$expectedImplementsWithTypesAnnotation."\n");
  71609. }
  71610. $implementsWithTypesPresent = true;
  71611. break;
  71612. }
  71613. }
  71614. if (!$templateTypeInputPresent || !$templateTypeComputedPresent || !$implementsWithTypesPresent) {
  71615. $lines = $doc->getLines();
  71616. $lastLine = end($lines);
  71617. \assert(false !== $lastLine);
  71618. $lastLine->setContent(
  71619. ''
  71620. .(!$templateTypeInputPresent ? ' * @'.$expectedTemplateTypeInputAnnotation."\n" : '')
  71621. .(!$templateTypeComputedPresent ? ' * @'.$expectedTemplateTypeComputedAnnotation."\n" : '')
  71622. .(!$implementsWithTypesPresent ? ' * @'.$expectedImplementsWithTypesAnnotation."\n" : '')
  71623. .$lastLine->getContent()
  71624. );
  71625. }
  71626. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  71627. }
  71628. private function getDocBlockIndex(Tokens $tokens, int $index): int
  71629. {
  71630. do {
  71631. $index = $tokens->getPrevNonWhitespace($index);
  71632. if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  71633. $index = $tokens->getPrevTokenOfKind($index, [[T_ATTRIBUTE]]);
  71634. }
  71635. } while ($tokens[$index]->isGivenKind(self::MODIFIERS));
  71636. return $index;
  71637. }
  71638. private function isPHPDoc(Tokens $tokens, int $index): bool
  71639. {
  71640. return $tokens[$index]->isGivenKind(T_DOC_COMMENT);
  71641. }
  71642. private function getExampleFixerFile(): \SplFileInfo
  71643. {
  71644. $reflection = new \ReflectionClass(ConstantCaseFixer::class);
  71645. $fileName = $reflection->getFileName();
  71646. if (false === $fileName) {
  71647. throw new \RuntimeException('Cannot read example fileName.');
  71648. }
  71649. return new \SplFileInfo($fileName);
  71650. }
  71651. private static function getShortClassName(string $longClassName): string
  71652. {
  71653. return \array_slice(explode('\\', $longClassName), -1)[0];
  71654. }
  71655. private function isTestForFixerFile(\SplFileInfo $file): bool
  71656. {
  71657. $basename = $file->getBasename('.php');
  71658. return str_ends_with($basename, 'FixerTest')
  71659. && !\in_array($basename, [
  71660. self::getShortClassName(AbstractFunctionReferenceFixerTest::class),
  71661. self::getShortClassName(AbstractFixerTest::class),
  71662. self::getShortClassName(AbstractProxyFixerTest::class),
  71663. ], true);
  71664. }
  71665. private function getFixerForSrcFile(\SplFileInfo $file): ?FixerInterface
  71666. {
  71667. $basename = $file->getBasename('.php');
  71668. if (!str_ends_with($basename, 'Fixer')) {
  71669. return null;
  71670. }
  71671. Preg::match('#.+src/(.+)\.php#', $file->getPathname(), $matches);
  71672. if (!isset($matches[1])) {
  71673. return null;
  71674. }
  71675. $className = 'PhpCsFixer\\'.str_replace('/', '\\', $matches[1]);
  71676. $implements = class_implements($className);
  71677. if (false === $implements || !isset($implements[ConfigurableFixerInterface::class])) {
  71678. return null;
  71679. }
  71680. if (AbstractPhpdocToTypeDeclarationFixer::class === $className) {
  71681. return new class extends AbstractPhpdocToTypeDeclarationFixer {
  71682. protected function isSkippedType(string $type): bool
  71683. {
  71684. throw new \LogicException('Not implemented.');
  71685. }
  71686. protected function createTokensFromRawType(string $type): Tokens
  71687. {
  71688. throw new \LogicException('Not implemented.');
  71689. }
  71690. public function getDefinition(): FixerDefinitionInterface
  71691. {
  71692. throw new \LogicException('Not implemented.');
  71693. }
  71694. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71695. {
  71696. throw new \LogicException('Not implemented.');
  71697. }
  71698. public function isCandidate(Tokens $tokens): bool
  71699. {
  71700. throw new \LogicException('Not implemented.');
  71701. }
  71702. };
  71703. } elseif (AbstractDoctrineAnnotationFixer::class === $className) {
  71704. return new class extends AbstractDoctrineAnnotationFixer {
  71705. protected function isSkippedType(string $type): bool
  71706. {
  71707. throw new \LogicException('Not implemented.');
  71708. }
  71709. protected function createTokensFromRawType(string $type): Tokens
  71710. {
  71711. throw new \LogicException('Not implemented.');
  71712. }
  71713. public function getDefinition(): FixerDefinitionInterface
  71714. {
  71715. throw new \LogicException('Not implemented.');
  71716. }
  71717. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71718. {
  71719. throw new \LogicException('Not implemented.');
  71720. }
  71721. public function isCandidate(Tokens $tokens): bool
  71722. {
  71723. throw new \LogicException('Not implemented.');
  71724. }
  71725. public function configure(array $configuration): void
  71726. {
  71727. }
  71728. protected function fixAnnotations(DoctrineAnnotationTokens $doctrineAnnotationTokens): void
  71729. {
  71730. throw new \LogicException('Not implemented.');
  71731. }
  71732. public function getConfigurationDefinition(): FixerConfigurationResolverInterface
  71733. {
  71734. return $this->createConfigurationDefinition();
  71735. }
  71736. };
  71737. }
  71738. $fixer = new $className();
  71739. \assert($fixer instanceof FixerInterface);
  71740. return $fixer;
  71741. }
  71742. }
  71743. <?php
  71744. declare(strict_types=1);
  71745. namespace PhpCsFixer\Fixer\Basic;
  71746. use PhpCsFixer\AbstractFixer;
  71747. use PhpCsFixer\FixerDefinition\CodeSample;
  71748. use PhpCsFixer\FixerDefinition\FixerDefinition;
  71749. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  71750. use PhpCsFixer\Tokenizer\FCT;
  71751. use PhpCsFixer\Tokenizer\Token;
  71752. use PhpCsFixer\Tokenizer\Tokens;
  71753. final class SingleLineEmptyBodyFixer extends AbstractFixer
  71754. {
  71755. public function getDefinition(): FixerDefinitionInterface
  71756. {
  71757. return new FixerDefinition(
  71758. 'Empty body of class, interface, trait, enum or function must be abbreviated as `{}` and placed on the same line as the previous symbol, separated by a single space.',
  71759. [new CodeSample('<?php function foo(
  71760. int $x
  71761. )
  71762. {
  71763. }
  71764. ')],
  71765. );
  71766. }
  71767. public function getPriority(): int
  71768. {
  71769. return -19;
  71770. }
  71771. public function isCandidate(Tokens $tokens): bool
  71772. {
  71773. return $tokens->isAnyTokenKindsFound([T_INTERFACE, T_CLASS, T_FUNCTION, T_TRAIT, FCT::T_ENUM]);
  71774. }
  71775. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71776. {
  71777. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  71778. if (!$tokens[$index]->isGivenKind([...Token::getClassyTokenKinds(), T_FUNCTION])) {
  71779. continue;
  71780. }
  71781. $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
  71782. if (!$tokens[$openBraceIndex]->equals('{')) {
  71783. continue;
  71784. }
  71785. $closeBraceIndex = $tokens->getNextNonWhitespace($openBraceIndex);
  71786. if (!$tokens[$closeBraceIndex]->equals('}')) {
  71787. continue;
  71788. }
  71789. $tokens->ensureWhitespaceAtIndex($openBraceIndex + 1, 0, '');
  71790. $beforeOpenBraceIndex = $tokens->getPrevNonWhitespace($openBraceIndex);
  71791. if (!$tokens[$beforeOpenBraceIndex]->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  71792. $tokens->ensureWhitespaceAtIndex($openBraceIndex - 1, 1, ' ');
  71793. }
  71794. }
  71795. }
  71796. }
  71797. <?php
  71798. declare(strict_types=1);
  71799. namespace PhpCsFixer\Fixer\Basic;
  71800. use PhpCsFixer\AbstractFixer;
  71801. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  71802. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  71803. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  71804. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  71805. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  71806. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  71807. use PhpCsFixer\FixerDefinition\CodeSample;
  71808. use PhpCsFixer\FixerDefinition\FixerDefinition;
  71809. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  71810. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  71811. use PhpCsFixer\Tokenizer\CT;
  71812. use PhpCsFixer\Tokenizer\Tokens;
  71813. /**
  71814. @phpstan-type
  71815. @phpstan-type
  71816. @implements
  71817. */
  71818. final class NoTrailingCommaInSinglelineFixer extends AbstractFixer implements ConfigurableFixerInterface
  71819. {
  71820. /**
  71821. @use */
  71822. use ConfigurableFixerTrait;
  71823. public function getDefinition(): FixerDefinitionInterface
  71824. {
  71825. return new FixerDefinition(
  71826. 'If a list of values separated by a comma is contained on a single line, then the last item MUST NOT have a trailing comma.',
  71827. [
  71828. new CodeSample("<?php\nfoo(\$a,);\n\$foo = array(1,);\n[\$foo, \$bar,] = \$array;\nuse a\\{ClassA, ClassB,};\n"),
  71829. new CodeSample("<?php\nfoo(\$a,);\n[\$foo, \$bar,] = \$array;\n", ['elements' => ['array_destructuring']]),
  71830. ]
  71831. );
  71832. }
  71833. public function isCandidate(Tokens $tokens): bool
  71834. {
  71835. return
  71836. $tokens->isTokenKindFound(',')
  71837. && $tokens->isAnyTokenKindsFound([')', CT::T_ARRAY_SQUARE_BRACE_CLOSE, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_CLOSE]);
  71838. }
  71839. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  71840. {
  71841. $elements = ['arguments', 'array', 'array_destructuring', 'group_import'];
  71842. return new FixerConfigurationResolver([
  71843. (new FixerOptionBuilder('elements', 'Which elements to fix.'))
  71844. ->setAllowedTypes(['string[]'])
  71845. ->setAllowedValues([new AllowedValueSubset($elements)])
  71846. ->setDefault($elements)
  71847. ->getOption(),
  71848. ]);
  71849. }
  71850. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  71851. {
  71852. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  71853. if (!$tokens[$index]->equals(')') && !$tokens[$index]->isGivenKind([CT::T_ARRAY_SQUARE_BRACE_CLOSE, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_CLOSE])) {
  71854. continue;
  71855. }
  71856. $commaIndex = $tokens->getPrevMeaningfulToken($index);
  71857. if (!$tokens[$commaIndex]->equals(',')) {
  71858. continue;
  71859. }
  71860. $block = Tokens::detectBlockType($tokens[$index]);
  71861. $blockOpenIndex = $tokens->findBlockStart($block['type'], $index);
  71862. if ($tokens->isPartialCodeMultiline($blockOpenIndex, $index)) {
  71863. continue;
  71864. }
  71865. if (!$this->shouldBeCleared($tokens, $blockOpenIndex)) {
  71866. continue;
  71867. }
  71868. do {
  71869. $tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
  71870. $commaIndex = $tokens->getPrevMeaningfulToken($commaIndex);
  71871. } while ($tokens[$commaIndex]->equals(','));
  71872. $tokens->removeTrailingWhitespace($commaIndex);
  71873. }
  71874. }
  71875. private function shouldBeCleared(Tokens $tokens, int $openIndex): bool
  71876. {
  71877. $elements = $this->configuration['elements'];
  71878. if ($tokens[$openIndex]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  71879. return \in_array('array', $elements, true);
  71880. }
  71881. if ($tokens[$openIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
  71882. return \in_array('array_destructuring', $elements, true);
  71883. }
  71884. if ($tokens[$openIndex]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  71885. return \in_array('group_import', $elements, true);
  71886. }
  71887. if (!$tokens[$openIndex]->equals('(')) {
  71888. return false;
  71889. }
  71890. $beforeOpen = $tokens->getPrevMeaningfulToken($openIndex);
  71891. if ($tokens[$beforeOpen]->isGivenKind(T_ARRAY)) {
  71892. return \in_array('array', $elements, true);
  71893. }
  71894. if ($tokens[$beforeOpen]->isGivenKind(T_LIST)) {
  71895. return \in_array('array_destructuring', $elements, true);
  71896. }
  71897. if ($tokens[$beforeOpen]->isGivenKind([T_UNSET, T_ISSET, T_VARIABLE, T_CLASS])) {
  71898. return \in_array('arguments', $elements, true);
  71899. }
  71900. if ($tokens[$beforeOpen]->isGivenKind(T_STRING)) {
  71901. return !AttributeAnalyzer::isAttribute($tokens, $beforeOpen) && \in_array('arguments', $elements, true);
  71902. }
  71903. if ($tokens[$beforeOpen]->equalsAny([')', ']', [CT::T_DYNAMIC_VAR_BRACE_CLOSE], [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE]])) {
  71904. $block = Tokens::detectBlockType($tokens[$beforeOpen]);
  71905. return
  71906. (
  71907. Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE === $block['type']
  71908. || Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE === $block['type']
  71909. || Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE === $block['type']
  71910. || Tokens::BLOCK_TYPE_PARENTHESIS_BRACE === $block['type']
  71911. ) && \in_array('arguments', $elements, true);
  71912. }
  71913. return false;
  71914. }
  71915. }
  71916. <?php
  71917. declare(strict_types=1);
  71918. namespace PhpCsFixer\Fixer\Basic;
  71919. use PhpCsFixer\AbstractFixer;
  71920. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  71921. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  71922. use PhpCsFixer\Fixer\Indentation;
  71923. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  71924. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  71925. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  71926. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  71927. use PhpCsFixer\FixerDefinition\CodeSample;
  71928. use PhpCsFixer\FixerDefinition\FixerDefinition;
  71929. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  71930. use PhpCsFixer\Preg;
  71931. use PhpCsFixer\Tokenizer\CT;
  71932. use PhpCsFixer\Tokenizer\FCT;
  71933. use PhpCsFixer\Tokenizer\Token;
  71934. use PhpCsFixer\Tokenizer\Tokens;
  71935. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  71936. /**
  71937. @phpstan-type
  71938. @phpstan-type
  71939. @implements
  71940. */
  71941. final class BracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  71942. {
  71943. /**
  71944. @use */
  71945. use ConfigurableFixerTrait;
  71946. use Indentation;
  71947. public const NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END = 'next_line_unless_newline_at_signature_end';
  71948. public const SAME_LINE = 'same_line';
  71949. private const CONTROL_STRUCTURE_TOKENS = [T_DECLARE, T_DO, T_ELSE, T_ELSEIF, T_FINALLY, T_FOR, T_FOREACH, T_IF, T_WHILE, T_TRY, T_CATCH, T_SWITCH, FCT::T_MATCH];
  71950. public function getDefinition(): FixerDefinitionInterface
  71951. {
  71952. return new FixerDefinition(
  71953. 'Braces must be placed as configured.',
  71954. [
  71955. new CodeSample(
  71956. '<?php
  71957. class Foo {
  71958. }
  71959. function foo() {
  71960. }
  71961. $foo = function()
  71962. {
  71963. };
  71964. if (foo())
  71965. {
  71966. bar();
  71967. }
  71968. $foo = new class
  71969. {
  71970. };
  71971. '
  71972. ),
  71973. new CodeSample(
  71974. '<?php
  71975. if (foo()) {
  71976. bar();
  71977. }
  71978. ',
  71979. ['control_structures_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
  71980. ),
  71981. new CodeSample(
  71982. '<?php
  71983. function foo()
  71984. {
  71985. }
  71986. ',
  71987. ['functions_opening_brace' => self::SAME_LINE]
  71988. ),
  71989. new CodeSample(
  71990. '<?php
  71991. $foo = function () {
  71992. };
  71993. ',
  71994. ['anonymous_functions_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
  71995. ),
  71996. new CodeSample(
  71997. '<?php
  71998. class Foo
  71999. {
  72000. }
  72001. ',
  72002. ['classes_opening_brace' => self::SAME_LINE]
  72003. ),
  72004. new CodeSample(
  72005. '<?php
  72006. $foo = new class {
  72007. };
  72008. ',
  72009. ['anonymous_classes_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
  72010. ),
  72011. new CodeSample(
  72012. '<?php
  72013. $foo = new class { };
  72014. $bar = new class { private $baz; };
  72015. ',
  72016. ['allow_single_line_empty_anonymous_classes' => true]
  72017. ),
  72018. new CodeSample(
  72019. '<?php
  72020. $foo = function () { return true; };
  72021. $bar = function () { $result = true;
  72022. return $result; };
  72023. ',
  72024. ['allow_single_line_anonymous_functions' => true]
  72025. ),
  72026. ]
  72027. );
  72028. }
  72029. public function isCandidate(Tokens $tokens): bool
  72030. {
  72031. return $tokens->isTokenKindFound('{');
  72032. }
  72033. public function getPriority(): int
  72034. {
  72035. return -2;
  72036. }
  72037. /**
  72038. @protected */
  72039. public function createConfigurationDefinition(): FixerConfigurationResolverInterface
  72040. {
  72041. return new FixerConfigurationResolver([
  72042. (new FixerOptionBuilder('control_structures_opening_brace', 'The position of the opening brace of control structures‘ body.'))
  72043. ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
  72044. ->setDefault(self::SAME_LINE)
  72045. ->getOption(),
  72046. (new FixerOptionBuilder('functions_opening_brace', 'The position of the opening brace of functions‘ body.'))
  72047. ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
  72048. ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
  72049. ->getOption(),
  72050. (new FixerOptionBuilder('anonymous_functions_opening_brace', 'The position of the opening brace of anonymous functions‘ body.'))
  72051. ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
  72052. ->setDefault(self::SAME_LINE)
  72053. ->getOption(),
  72054. (new FixerOptionBuilder('classes_opening_brace', 'The position of the opening brace of classes‘ body.'))
  72055. ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
  72056. ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
  72057. ->getOption(),
  72058. (new FixerOptionBuilder('anonymous_classes_opening_brace', 'The position of the opening brace of anonymous classes‘ body.'))
  72059. ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
  72060. ->setDefault(self::SAME_LINE)
  72061. ->getOption(),
  72062. (new FixerOptionBuilder('allow_single_line_empty_anonymous_classes', 'Allow anonymous classes to have opening and closing braces on the same line.'))
  72063. ->setAllowedTypes(['bool'])
  72064. ->setDefault(true)
  72065. ->getOption(),
  72066. (new FixerOptionBuilder('allow_single_line_anonymous_functions', 'Allow anonymous functions to have opening and closing braces on the same line.'))
  72067. ->setAllowedTypes(['bool'])
  72068. ->setDefault(true)
  72069. ->getOption(),
  72070. ]);
  72071. }
  72072. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  72073. {
  72074. $classyTokens = Token::getClassyTokenKinds();
  72075. $tokensAnalyzer = new TokensAnalyzer($tokens);
  72076. $allowSingleLineUntil = null;
  72077. foreach ($tokens as $index => $token) {
  72078. $allowSingleLine = false;
  72079. $allowSingleLineIfEmpty = false;
  72080. if ($token->isGivenKind($classyTokens)) {
  72081. $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
  72082. if ($tokensAnalyzer->isAnonymousClass($index)) {
  72083. $allowSingleLineIfEmpty = true === $this->configuration['allow_single_line_empty_anonymous_classes'];
  72084. $positionOption = 'anonymous_classes_opening_brace';
  72085. } else {
  72086. $positionOption = 'classes_opening_brace';
  72087. }
  72088. } elseif ($token->isGivenKind(T_FUNCTION)) {
  72089. $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]]);
  72090. if (!$tokens[$openBraceIndex]->equals('{')) {
  72091. continue;
  72092. }
  72093. if ($tokensAnalyzer->isLambda($index)) {
  72094. $allowSingleLine = true === $this->configuration['allow_single_line_anonymous_functions'];
  72095. $positionOption = 'anonymous_functions_opening_brace';
  72096. } else {
  72097. $positionOption = 'functions_opening_brace';
  72098. }
  72099. } elseif ($token->isGivenKind(self::CONTROL_STRUCTURE_TOKENS)) {
  72100. $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
  72101. $openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
  72102. if (!$tokens[$openBraceIndex]->equals('{')) {
  72103. continue;
  72104. }
  72105. $positionOption = 'control_structures_opening_brace';
  72106. } elseif ($token->isGivenKind(T_VARIABLE)) {
  72107. $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';', [CT::T_PROPERTY_HOOK_BRACE_OPEN], [T_CLOSE_TAG]]);
  72108. if (!$tokens[$openBraceIndex]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
  72109. continue;
  72110. }
  72111. $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PROPERTY_HOOK, $openBraceIndex);
  72112. if (!$tokens->isPartialCodeMultiline($openBraceIndex, $closeBraceIndex)) {
  72113. continue;
  72114. }
  72115. $positionOption = 'control_structures_opening_brace';
  72116. } else {
  72117. continue;
  72118. }
  72119. $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openBraceIndex);
  72120. $addNewlinesInsideBraces = true;
  72121. if ($allowSingleLine || $allowSingleLineIfEmpty || $index < $allowSingleLineUntil) {
  72122. $addNewlinesInsideBraces = false;
  72123. for ($indexInsideBraces = $openBraceIndex + 1; $indexInsideBraces < $closeBraceIndex; ++$indexInsideBraces) {
  72124. $tokenInsideBraces = $tokens[$indexInsideBraces];
  72125. if (
  72126. ($allowSingleLineIfEmpty && !$tokenInsideBraces->isWhitespace() && !$tokenInsideBraces->isComment())
  72127. || ($tokenInsideBraces->isWhitespace() && Preg::match('/\R/', $tokenInsideBraces->getContent()))
  72128. ) {
  72129. $addNewlinesInsideBraces = true;
  72130. break;
  72131. }
  72132. }
  72133. if (!$addNewlinesInsideBraces && null === $allowSingleLineUntil) {
  72134. $allowSingleLineUntil = $closeBraceIndex;
  72135. }
  72136. }
  72137. if (
  72138. $addNewlinesInsideBraces
  72139. && !$this->isFollowedByNewLine($tokens, $openBraceIndex)
  72140. && !$this->hasCommentOnSameLine($tokens, $openBraceIndex)
  72141. && !$tokens[$tokens->getNextMeaningfulToken($openBraceIndex)]->isGivenKind(T_CLOSE_TAG)
  72142. ) {
  72143. $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
  72144. if ($tokens->ensureWhitespaceAtIndex($openBraceIndex + 1, 0, $whitespace)) {
  72145. ++$closeBraceIndex;
  72146. }
  72147. }
  72148. $whitespace = ' ';
  72149. if (self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END === $this->configuration[$positionOption]) {
  72150. $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
  72151. $previousTokenIndex = $openBraceIndex;
  72152. do {
  72153. $previousTokenIndex = $tokens->getPrevMeaningfulToken($previousTokenIndex);
  72154. } while ($tokens[$previousTokenIndex]->isGivenKind([CT::T_TYPE_COLON, CT::T_NULLABLE_TYPE, T_STRING, T_NS_SEPARATOR, CT::T_ARRAY_TYPEHINT, T_STATIC, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, T_CALLABLE, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE]));
  72155. if ($tokens[$previousTokenIndex]->equals(')')) {
  72156. if ($tokens[--$previousTokenIndex]->isComment()) {
  72157. --$previousTokenIndex;
  72158. }
  72159. if (
  72160. $tokens[$previousTokenIndex]->isWhitespace()
  72161. && Preg::match('/\R/', $tokens[$previousTokenIndex]->getContent())
  72162. ) {
  72163. $whitespace = ' ';
  72164. }
  72165. }
  72166. }
  72167. $moveBraceToIndex = null;
  72168. if (' ' === $whitespace) {
  72169. $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($openBraceIndex);
  72170. for ($indexBeforeOpenBrace = $openBraceIndex - 1; $indexBeforeOpenBrace > $previousMeaningfulIndex; --$indexBeforeOpenBrace) {
  72171. if (!$tokens[$indexBeforeOpenBrace]->isComment()) {
  72172. continue;
  72173. }
  72174. $tokenBeforeOpenBrace = $tokens[--$indexBeforeOpenBrace];
  72175. if ($tokenBeforeOpenBrace->isWhitespace()) {
  72176. $moveBraceToIndex = $indexBeforeOpenBrace;
  72177. } elseif ($indexBeforeOpenBrace === $previousMeaningfulIndex) {
  72178. $moveBraceToIndex = $previousMeaningfulIndex + 1;
  72179. }
  72180. }
  72181. } elseif (!$tokens[$openBraceIndex - 1]->isWhitespace() || !Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
  72182. for ($indexAfterOpenBrace = $openBraceIndex + 1; $indexAfterOpenBrace < $closeBraceIndex; ++$indexAfterOpenBrace) {
  72183. if ($tokens[$indexAfterOpenBrace]->isWhitespace() && Preg::match('/\R/', $tokens[$indexAfterOpenBrace]->getContent())) {
  72184. break;
  72185. }
  72186. if ($tokens[$indexAfterOpenBrace]->isComment() && !str_starts_with($tokens[$indexAfterOpenBrace]->getContent(), '/*')) {
  72187. $moveBraceToIndex = $indexAfterOpenBrace + 1;
  72188. }
  72189. }
  72190. }
  72191. if (null !== $moveBraceToIndex) {
  72192. $movedToken = clone $tokens[$openBraceIndex];
  72193. $delta = $openBraceIndex < $moveBraceToIndex ? 1 : -1;
  72194. if ($tokens[$openBraceIndex + $delta]->isWhitespace()) {
  72195. if (-1 === $delta && Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
  72196. $content = Preg::replace('/^(\h*?\R)?\h*/', '', $tokens[$openBraceIndex + 1]->getContent());
  72197. if ('' !== $content) {
  72198. $tokens[$openBraceIndex + 1] = new Token([T_WHITESPACE, $content]);
  72199. } else {
  72200. $tokens->clearAt($openBraceIndex + 1);
  72201. }
  72202. } elseif ($tokens[$openBraceIndex - 1]->isWhitespace()) {
  72203. $tokens->clearAt($openBraceIndex - 1);
  72204. }
  72205. }
  72206. for ($i = $openBraceIndex; $i !== $moveBraceToIndex; $i += $delta) {
  72207. $siblingToken = $tokens[$i + $delta];
  72208. $tokens[$i] = $siblingToken;
  72209. }
  72210. $tokens[$i] = $movedToken;
  72211. if ($tokens[$openBraceIndex]->isWhitespace() && $tokens[$openBraceIndex + 1]->isWhitespace()) {
  72212. $tokens[$openBraceIndex] = new Token([
  72213. T_WHITESPACE,
  72214. $tokens[$openBraceIndex]->getContent().$tokens[$openBraceIndex + 1]->getContent(),
  72215. ]);
  72216. $tokens->clearAt($openBraceIndex + 1);
  72217. }
  72218. $openBraceIndex = $moveBraceToIndex;
  72219. }
  72220. if ($tokens->ensureWhitespaceAtIndex($openBraceIndex - 1, 1, $whitespace)) {
  72221. ++$closeBraceIndex;
  72222. if (null !== $allowSingleLineUntil) {
  72223. ++$allowSingleLineUntil;
  72224. }
  72225. }
  72226. if (
  72227. !$addNewlinesInsideBraces
  72228. || $tokens[$tokens->getPrevMeaningfulToken($closeBraceIndex)]->isGivenKind(T_OPEN_TAG)
  72229. ) {
  72230. continue;
  72231. }
  72232. $prevIndex = $closeBraceIndex - 1;
  72233. while ($tokens->isEmptyAt($prevIndex)) {
  72234. --$prevIndex;
  72235. }
  72236. $prevToken = $tokens[$prevIndex];
  72237. if ($prevToken->isWhitespace() && Preg::match('/\R/', $prevToken->getContent())) {
  72238. continue;
  72239. }
  72240. $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
  72241. $tokens->ensureWhitespaceAtIndex($prevIndex, 1, $whitespace);
  72242. }
  72243. }
  72244. private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
  72245. {
  72246. $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
  72247. $nextToken = $tokens[$nextIndex];
  72248. if (!$nextToken->equals('(')) {
  72249. return $structureTokenIndex;
  72250. }
  72251. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  72252. }
  72253. private function isFollowedByNewLine(Tokens $tokens, int $index): bool
  72254. {
  72255. for (++$index, $max = \count($tokens) - 1; $index < $max; ++$index) {
  72256. $token = $tokens[$index];
  72257. if (!$token->isComment()) {
  72258. return $token->isWhitespace() && Preg::match('/\R/', $token->getContent());
  72259. }
  72260. }
  72261. return false;
  72262. }
  72263. private function hasCommentOnSameLine(Tokens $tokens, int $index): bool
  72264. {
  72265. $token = $tokens[$index + 1];
  72266. if ($token->isWhitespace() && !Preg::match('/\R/', $token->getContent())) {
  72267. $token = $tokens[$index + 2];
  72268. }
  72269. return $token->isComment();
  72270. }
  72271. }
  72272. <?php
  72273. declare(strict_types=1);
  72274. namespace PhpCsFixer\Fixer\Basic;
  72275. use PhpCsFixer\AbstractFixer;
  72276. use PhpCsFixer\FixerDefinition\CodeSample;
  72277. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72278. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72279. use PhpCsFixer\Tokenizer\Token;
  72280. use PhpCsFixer\Tokenizer\Tokens;
  72281. final class EncodingFixer extends AbstractFixer
  72282. {
  72283. private string $bom;
  72284. public function __construct()
  72285. {
  72286. parent::__construct();
  72287. $this->bom = pack('CCC', 0xEF, 0xBB, 0xBF);
  72288. }
  72289. public function getDefinition(): FixerDefinitionInterface
  72290. {
  72291. return new FixerDefinition(
  72292. 'PHP code MUST use only UTF-8 without BOM (remove BOM).',
  72293. [
  72294. new CodeSample(
  72295. $this->bom.'<?php
  72296. echo "Hello!";
  72297. '
  72298. ),
  72299. ]
  72300. );
  72301. }
  72302. public function getPriority(): int
  72303. {
  72304. return 100;
  72305. }
  72306. public function isCandidate(Tokens $tokens): bool
  72307. {
  72308. return true;
  72309. }
  72310. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  72311. {
  72312. $content = $tokens[0]->getContent();
  72313. if (str_starts_with($content, $this->bom)) {
  72314. $newContent = substr($content, 3);
  72315. if ('' === $newContent) {
  72316. $tokens->clearAt(0);
  72317. } else {
  72318. $tokens[0] = new Token([$tokens[0]->getId(), $newContent]);
  72319. }
  72320. }
  72321. }
  72322. }
  72323. <?php
  72324. declare(strict_types=1);
  72325. namespace PhpCsFixer\Fixer\Basic;
  72326. use PhpCsFixer\AbstractFixer;
  72327. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  72328. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  72329. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  72330. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  72331. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  72332. use PhpCsFixer\FixerDefinition\CodeSample;
  72333. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72334. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72335. use PhpCsFixer\Preg;
  72336. use PhpCsFixer\Tokenizer\Token;
  72337. use PhpCsFixer\Tokenizer\Tokens;
  72338. /**
  72339. @phpstan-type
  72340. @phpstan-type
  72341. @implements
  72342. */
  72343. final class NonPrintableCharacterFixer extends AbstractFixer implements ConfigurableFixerInterface
  72344. {
  72345. /**
  72346. @use */
  72347. use ConfigurableFixerTrait;
  72348. private const TOKENS = [
  72349. T_STRING_VARNAME,
  72350. T_INLINE_HTML,
  72351. T_VARIABLE,
  72352. T_COMMENT,
  72353. T_ENCAPSED_AND_WHITESPACE,
  72354. T_CONSTANT_ENCAPSED_STRING,
  72355. T_DOC_COMMENT,
  72356. ];
  72357. private array $symbolsReplace;
  72358. public function __construct()
  72359. {
  72360. parent::__construct();
  72361. $this->symbolsReplace = [
  72362. pack('H*', 'e2808b') => ['', '200b'],
  72363. pack('H*', 'e28087') => [' ', '2007'],
  72364. pack('H*', 'e280af') => [' ', '202f'],
  72365. pack('H*', 'e281a0') => ['', '2060'],
  72366. pack('H*', 'c2a0') => [' ', 'a0'],
  72367. ];
  72368. }
  72369. public function getDefinition(): FixerDefinitionInterface
  72370. {
  72371. return new FixerDefinition(
  72372. 'Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.',
  72373. [
  72374. new CodeSample(
  72375. '<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n"
  72376. ),
  72377. new CodeSample(
  72378. '<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n",
  72379. ['use_escape_sequences_in_strings' => false]
  72380. ),
  72381. ],
  72382. null,
  72383. 'Risky when strings contain intended invisible characters.'
  72384. );
  72385. }
  72386. public function isRisky(): bool
  72387. {
  72388. return true;
  72389. }
  72390. public function isCandidate(Tokens $tokens): bool
  72391. {
  72392. return $tokens->isAnyTokenKindsFound(self::TOKENS);
  72393. }
  72394. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  72395. {
  72396. return new FixerConfigurationResolver([
  72397. (new FixerOptionBuilder('use_escape_sequences_in_strings', 'Whether characters should be replaced with escape sequences in strings.'))
  72398. ->setAllowedTypes(['bool'])
  72399. ->setDefault(true)
  72400. ->getOption(),
  72401. ]);
  72402. }
  72403. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  72404. {
  72405. $replacements = [];
  72406. $escapeSequences = [];
  72407. foreach ($this->symbolsReplace as $character => [$replacement, $codepoint]) {
  72408. $replacements[$character] = $replacement;
  72409. $escapeSequences[$character] = '\u{'.$codepoint.'}';
  72410. }
  72411. foreach ($tokens as $index => $token) {
  72412. $content = $token->getContent();
  72413. if (
  72414. true === $this->configuration['use_escape_sequences_in_strings']
  72415. && $token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE])
  72416. ) {
  72417. if (!Preg::match('/'.implode('|', array_keys($escapeSequences)).'/', $content)) {
  72418. continue;
  72419. }
  72420. $previousToken = $tokens[$index - 1];
  72421. $stringTypeChanged = false;
  72422. $swapQuotes = false;
  72423. if ($previousToken->isGivenKind(T_START_HEREDOC)) {
  72424. $previousTokenContent = $previousToken->getContent();
  72425. if (str_contains($previousTokenContent, '\'')) {
  72426. $tokens[$index - 1] = new Token([T_START_HEREDOC, str_replace('\'', '', $previousTokenContent)]);
  72427. $stringTypeChanged = true;
  72428. }
  72429. } elseif (str_starts_with($content, "'")) {
  72430. $stringTypeChanged = true;
  72431. $swapQuotes = true;
  72432. }
  72433. if ($swapQuotes) {
  72434. $content = str_replace("\\'", "'", $content);
  72435. }
  72436. if ($stringTypeChanged) {
  72437. $content = Preg::replace('/(\\\{1,2})/', '\\\\\\\\', $content);
  72438. $content = str_replace('$', '\$', $content);
  72439. }
  72440. if ($swapQuotes) {
  72441. $content = str_replace('"', '\"', $content);
  72442. $content = Preg::replace('/^\'(.*)\'$/s', '"$1"', $content);
  72443. }
  72444. $tokens[$index] = new Token([$token->getId(), strtr($content, $escapeSequences)]);
  72445. continue;
  72446. }
  72447. if ($token->isGivenKind(self::TOKENS)) {
  72448. $newContent = strtr($content, $replacements);
  72449. if ($token->isGivenKind([T_STRING_VARNAME, T_VARIABLE]) && str_contains($newContent, ' ')) {
  72450. continue;
  72451. }
  72452. if ($token->isGivenKind([T_COMMENT, T_DOC_COMMENT]) && str_starts_with($newContent, '/*') && strpos($newContent, '*/') !== \strlen($newContent) - 2) {
  72453. continue;
  72454. }
  72455. $tokens[$index] = new Token([$token->getId(), $newContent]);
  72456. }
  72457. }
  72458. }
  72459. }
  72460. <?php
  72461. declare(strict_types=1);
  72462. namespace PhpCsFixer\Fixer\Basic;
  72463. use PhpCsFixer\AbstractProxyFixer;
  72464. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  72465. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  72466. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  72467. use PhpCsFixer\Fixer\Indentation;
  72468. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  72469. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  72470. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72471. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72472. /**
  72473. @phpstan-type
  72474. @phpstan-type
  72475. @implements
  72476. */
  72477. final class CurlyBracesPositionFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface, WhitespacesAwareFixerInterface
  72478. {
  72479. /**
  72480. @use */
  72481. use ConfigurableFixerTrait;
  72482. use Indentation;
  72483. public const NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END = 'next_line_unless_newline_at_signature_end';
  72484. public const SAME_LINE = 'same_line';
  72485. private BracesPositionFixer $bracesPositionFixer;
  72486. public function __construct()
  72487. {
  72488. $this->bracesPositionFixer = new BracesPositionFixer();
  72489. parent::__construct();
  72490. }
  72491. public function getDefinition(): FixerDefinitionInterface
  72492. {
  72493. $fixerDefinition = $this->bracesPositionFixer->getDefinition();
  72494. return new FixerDefinition(
  72495. 'Curly braces must be placed as configured.',
  72496. $fixerDefinition->getCodeSamples(),
  72497. $fixerDefinition->getDescription(),
  72498. $fixerDefinition->getRiskyDescription()
  72499. );
  72500. }
  72501. public function getPriority(): int
  72502. {
  72503. return $this->bracesPositionFixer->getPriority();
  72504. }
  72505. public function getSuccessorsNames(): array
  72506. {
  72507. return [
  72508. $this->bracesPositionFixer->getName(),
  72509. ];
  72510. }
  72511. protected function configurePreNormalisation(array $configuration): void
  72512. {
  72513. $this->bracesPositionFixer->configure($configuration);
  72514. }
  72515. protected function createProxyFixers(): array
  72516. {
  72517. return [
  72518. $this->bracesPositionFixer,
  72519. ];
  72520. }
  72521. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  72522. {
  72523. return $this->bracesPositionFixer->createConfigurationDefinition();
  72524. }
  72525. }
  72526. <?php
  72527. declare(strict_types=1);
  72528. namespace PhpCsFixer\Fixer\Basic;
  72529. use PhpCsFixer\AbstractProxyFixer;
  72530. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  72531. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  72532. use PhpCsFixer\Fixer\ControlStructure\ControlStructureBracesFixer;
  72533. use PhpCsFixer\Fixer\ControlStructure\ControlStructureContinuationPositionFixer;
  72534. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  72535. use PhpCsFixer\Fixer\LanguageConstruct\DeclareParenthesesFixer;
  72536. use PhpCsFixer\Fixer\LanguageConstruct\SingleSpaceAroundConstructFixer;
  72537. use PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer;
  72538. use PhpCsFixer\Fixer\Whitespace\StatementIndentationFixer;
  72539. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  72540. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  72541. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  72542. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  72543. use PhpCsFixer\FixerDefinition\CodeSample;
  72544. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72545. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72546. /**
  72547. @phpstan-type
  72548. @phpstan-type
  72549. @implements
  72550. */
  72551. final class BracesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface, DeprecatedFixerInterface
  72552. {
  72553. /**
  72554. @use */
  72555. use ConfigurableFixerTrait;
  72556. public const LINE_NEXT = 'next';
  72557. public const LINE_SAME = 'same';
  72558. private ?BracesPositionFixer $bracesPositionFixer = null;
  72559. private ?ControlStructureContinuationPositionFixer $controlStructureContinuationPositionFixer = null;
  72560. public function getDefinition(): FixerDefinitionInterface
  72561. {
  72562. return new FixerDefinition(
  72563. 'The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.',
  72564. [
  72565. new CodeSample(
  72566. '<?php
  72567. class Foo {
  72568. public function bar($baz) {
  72569. if ($baz = 900) echo "Hello!";
  72570. if ($baz = 9000)
  72571. echo "Wait!";
  72572. if ($baz == true)
  72573. {
  72574. echo "Why?";
  72575. }
  72576. else
  72577. {
  72578. echo "Ha?";
  72579. }
  72580. if (is_array($baz))
  72581. foreach ($baz as $b)
  72582. {
  72583. echo $b;
  72584. }
  72585. }
  72586. }
  72587. '
  72588. ),
  72589. new CodeSample(
  72590. '<?php
  72591. $positive = function ($item) { return $item >= 0; };
  72592. $negative = function ($item) {
  72593. return $item < 0; };
  72594. ',
  72595. ['allow_single_line_closure' => true]
  72596. ),
  72597. new CodeSample(
  72598. '<?php
  72599. class Foo
  72600. {
  72601. public function bar($baz)
  72602. {
  72603. if ($baz = 900) echo "Hello!";
  72604. if ($baz = 9000)
  72605. echo "Wait!";
  72606. if ($baz == true)
  72607. {
  72608. echo "Why?";
  72609. }
  72610. else
  72611. {
  72612. echo "Ha?";
  72613. }
  72614. if (is_array($baz))
  72615. foreach ($baz as $b)
  72616. {
  72617. echo $b;
  72618. }
  72619. }
  72620. }
  72621. ',
  72622. ['position_after_functions_and_oop_constructs' => self::LINE_SAME]
  72623. ),
  72624. ]
  72625. );
  72626. }
  72627. public function getPriority(): int
  72628. {
  72629. return 35;
  72630. }
  72631. public function getSuccessorsNames(): array
  72632. {
  72633. return array_keys($this->proxyFixers);
  72634. }
  72635. protected function configurePostNormalisation(): void
  72636. {
  72637. $this->getBracesPositionFixer()->configure([
  72638. 'control_structures_opening_brace' => $this->translatePositionOption($this->configuration['position_after_control_structures']),
  72639. 'functions_opening_brace' => $this->translatePositionOption($this->configuration['position_after_functions_and_oop_constructs']),
  72640. 'anonymous_functions_opening_brace' => $this->translatePositionOption($this->configuration['position_after_anonymous_constructs']),
  72641. 'classes_opening_brace' => $this->translatePositionOption($this->configuration['position_after_functions_and_oop_constructs']),
  72642. 'anonymous_classes_opening_brace' => $this->translatePositionOption($this->configuration['position_after_anonymous_constructs']),
  72643. 'allow_single_line_empty_anonymous_classes' => $this->configuration['allow_single_line_anonymous_class_with_empty_body'],
  72644. 'allow_single_line_anonymous_functions' => $this->configuration['allow_single_line_closure'],
  72645. ]);
  72646. $this->getControlStructureContinuationPositionFixer()->configure([
  72647. 'position' => self::LINE_NEXT === $this->configuration['position_after_control_structures']
  72648. ? ControlStructureContinuationPositionFixer::NEXT_LINE
  72649. : ControlStructureContinuationPositionFixer::SAME_LINE,
  72650. ]);
  72651. }
  72652. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  72653. {
  72654. return new FixerConfigurationResolver([
  72655. (new FixerOptionBuilder('allow_single_line_anonymous_class_with_empty_body', 'Whether single line anonymous class with empty body notation should be allowed.'))
  72656. ->setAllowedTypes(['bool'])
  72657. ->setDefault(false)
  72658. ->getOption(),
  72659. (new FixerOptionBuilder('allow_single_line_closure', 'Whether single line lambda notation should be allowed.'))
  72660. ->setAllowedTypes(['bool'])
  72661. ->setDefault(false)
  72662. ->getOption(),
  72663. (new FixerOptionBuilder('position_after_functions_and_oop_constructs', 'Whether the opening brace should be placed on "next" or "same" line after classy constructs (non-anonymous classes, interfaces, traits, methods and non-lambda functions).'))
  72664. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  72665. ->setDefault(self::LINE_NEXT)
  72666. ->getOption(),
  72667. (new FixerOptionBuilder('position_after_control_structures', 'Whether the opening brace should be placed on "next" or "same" line after control structures.'))
  72668. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  72669. ->setDefault(self::LINE_SAME)
  72670. ->getOption(),
  72671. (new FixerOptionBuilder('position_after_anonymous_constructs', 'Whether the opening brace should be placed on "next" or "same" line after anonymous constructs (anonymous classes and lambda functions).'))
  72672. ->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
  72673. ->setDefault(self::LINE_SAME)
  72674. ->getOption(),
  72675. ]);
  72676. }
  72677. protected function createProxyFixers(): array
  72678. {
  72679. $singleSpaceAroundConstructFixer = new SingleSpaceAroundConstructFixer();
  72680. $singleSpaceAroundConstructFixer->configure([
  72681. 'constructs_contain_a_single_space' => [],
  72682. 'constructs_followed_by_a_single_space' => ['elseif', 'for', 'foreach', 'if', 'match', 'while', 'use_lambda'],
  72683. 'constructs_preceded_by_a_single_space' => ['use_lambda'],
  72684. ]);
  72685. $noExtraBlankLinesFixer = new NoExtraBlankLinesFixer();
  72686. $noExtraBlankLinesFixer->configure([
  72687. 'tokens' => ['curly_brace_block'],
  72688. ]);
  72689. return [
  72690. $singleSpaceAroundConstructFixer,
  72691. new ControlStructureBracesFixer(),
  72692. $noExtraBlankLinesFixer,
  72693. $this->getBracesPositionFixer(),
  72694. $this->getControlStructureContinuationPositionFixer(),
  72695. new DeclareParenthesesFixer(),
  72696. new NoMultipleStatementsPerLineFixer(),
  72697. new StatementIndentationFixer(true),
  72698. ];
  72699. }
  72700. private function getBracesPositionFixer(): BracesPositionFixer
  72701. {
  72702. if (null === $this->bracesPositionFixer) {
  72703. $this->bracesPositionFixer = new BracesPositionFixer();
  72704. }
  72705. return $this->bracesPositionFixer;
  72706. }
  72707. private function getControlStructureContinuationPositionFixer(): ControlStructureContinuationPositionFixer
  72708. {
  72709. if (null === $this->controlStructureContinuationPositionFixer) {
  72710. $this->controlStructureContinuationPositionFixer = new ControlStructureContinuationPositionFixer();
  72711. }
  72712. return $this->controlStructureContinuationPositionFixer;
  72713. }
  72714. private function translatePositionOption(string $option): string
  72715. {
  72716. return self::LINE_NEXT === $option
  72717. ? BracesPositionFixer::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END
  72718. : BracesPositionFixer::SAME_LINE;
  72719. }
  72720. }
  72721. <?php
  72722. declare(strict_types=1);
  72723. namespace PhpCsFixer\Fixer\Basic;
  72724. use PhpCsFixer\AbstractFixer;
  72725. use PhpCsFixer\DocBlock\TypeExpression;
  72726. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  72727. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  72728. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  72729. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  72730. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  72731. use PhpCsFixer\FixerDefinition\FileSpecificCodeSample;
  72732. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72733. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72734. use PhpCsFixer\Preg;
  72735. use PhpCsFixer\StdinFileInfo;
  72736. use PhpCsFixer\Tokenizer\Token;
  72737. use PhpCsFixer\Tokenizer\Tokens;
  72738. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  72739. /**
  72740. @phpstan-type
  72741. @phpstan-type
  72742. @implements
  72743. */
  72744. final class PsrAutoloadingFixer extends AbstractFixer implements ConfigurableFixerInterface
  72745. {
  72746. /**
  72747. @use */
  72748. use ConfigurableFixerTrait;
  72749. public function getDefinition(): FixerDefinitionInterface
  72750. {
  72751. return new FixerDefinition(
  72752. 'Classes must be in a path that matches their namespace, be at least one namespace deep and the class name should match the file name.',
  72753. [
  72754. new FileSpecificCodeSample(
  72755. '<?php
  72756. namespace PhpCsFixer\FIXER\Basic;
  72757. class InvalidName {}
  72758. ',
  72759. new \SplFileInfo(__FILE__)
  72760. ),
  72761. new FileSpecificCodeSample(
  72762. '<?php
  72763. namespace PhpCsFixer\FIXER\Basic;
  72764. class InvalidName {}
  72765. ',
  72766. new \SplFileInfo(__FILE__),
  72767. ['dir' => './src']
  72768. ),
  72769. ],
  72770. null,
  72771. 'This fixer may change your class name, which will break the code that depends on the old name.'
  72772. );
  72773. }
  72774. public function isCandidate(Tokens $tokens): bool
  72775. {
  72776. return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
  72777. }
  72778. public function isRisky(): bool
  72779. {
  72780. return true;
  72781. }
  72782. public function getPriority(): int
  72783. {
  72784. return -10;
  72785. }
  72786. public function supports(\SplFileInfo $file): bool
  72787. {
  72788. if ($file instanceof StdinFileInfo) {
  72789. return false;
  72790. }
  72791. if (
  72792. ('php' !== $file->getExtension())
  72793. || !Preg::match('/^'.TypeExpression::REGEX_IDENTIFIER.'$/', $file->getBasename('.php'))
  72794. ) {
  72795. return false;
  72796. }
  72797. try {
  72798. $tokens = Tokens::fromCode(\sprintf('<?php class %s {}', $file->getBasename('.php')));
  72799. if ($tokens[3]->isKeyword() || $tokens[3]->isMagicConstant()) {
  72800. return false;
  72801. }
  72802. } catch (\ParseError $e) {
  72803. return false;
  72804. }
  72805. return !Preg::match('{[/\\\](stub|fixture)s?[/\\\]}i', $file->getRealPath());
  72806. }
  72807. protected function configurePostNormalisation(): void
  72808. {
  72809. if (null !== $this->configuration['dir']) {
  72810. $realpath = realpath($this->configuration['dir']);
  72811. if (false === $realpath) {
  72812. throw new \InvalidArgumentException(\sprintf('Failed to resolve configured directory "%s".', $this->configuration['dir']));
  72813. }
  72814. $this->configuration['dir'] = $realpath;
  72815. }
  72816. }
  72817. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  72818. {
  72819. return new FixerConfigurationResolver([
  72820. (new FixerOptionBuilder('dir', 'If provided, the directory where the project code is placed.'))
  72821. ->setAllowedTypes(['null', 'string'])
  72822. ->setDefault(null)
  72823. ->getOption(),
  72824. ]);
  72825. }
  72826. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  72827. {
  72828. $tokenAnalyzer = new TokensAnalyzer($tokens);
  72829. if (null !== $this->configuration['dir'] && !str_starts_with($file->getRealPath(), $this->configuration['dir'])) {
  72830. return;
  72831. }
  72832. $namespace = null;
  72833. $namespaceStartIndex = null;
  72834. $namespaceEndIndex = null;
  72835. $classyName = null;
  72836. $classyIndex = null;
  72837. foreach ($tokens as $index => $token) {
  72838. if ($token->isGivenKind(T_NAMESPACE)) {
  72839. if (null !== $namespace) {
  72840. return;
  72841. }
  72842. $namespaceStartIndex = $tokens->getNextMeaningfulToken($index);
  72843. $namespaceEndIndex = $tokens->getNextTokenOfKind($namespaceStartIndex, [';']);
  72844. $namespace = trim($tokens->generatePartialCode($namespaceStartIndex, $namespaceEndIndex - 1));
  72845. } elseif ($token->isClassy()) {
  72846. if ($tokenAnalyzer->isAnonymousClass($index)) {
  72847. continue;
  72848. }
  72849. if (null !== $classyName) {
  72850. return;
  72851. }
  72852. $classyIndex = $tokens->getNextMeaningfulToken($index);
  72853. $classyName = $tokens[$classyIndex]->getContent();
  72854. }
  72855. }
  72856. if (null === $classyName) {
  72857. return;
  72858. }
  72859. $expectedClassyName = $this->calculateClassyName($file, $namespace, $classyName);
  72860. if ($classyName !== $expectedClassyName) {
  72861. $tokens[$classyIndex] = new Token([T_STRING, $expectedClassyName]);
  72862. }
  72863. if (null === $this->configuration['dir'] || null === $namespace) {
  72864. return;
  72865. }
  72866. if (!is_dir($this->configuration['dir'])) {
  72867. return;
  72868. }
  72869. $configuredDir = realpath($this->configuration['dir']);
  72870. $fileDir = \dirname($file->getRealPath());
  72871. if (\strlen($configuredDir) >= \strlen($fileDir)) {
  72872. return;
  72873. }
  72874. $newNamespace = substr(str_replace('/', '\\', $fileDir), \strlen($configuredDir) + 1);
  72875. $originalNamespace = substr($namespace, -\strlen($newNamespace));
  72876. if ($originalNamespace !== $newNamespace && strtolower($originalNamespace) === strtolower($newNamespace)) {
  72877. $tokens->clearRange($namespaceStartIndex, $namespaceEndIndex);
  72878. $namespace = substr($namespace, 0, -\strlen($newNamespace)).$newNamespace;
  72879. $newNamespace = Tokens::fromCode('<?php namespace '.$namespace.';');
  72880. $newNamespace->clearRange(0, 2);
  72881. $newNamespace->clearEmptyTokens();
  72882. $tokens->insertAt($namespaceStartIndex, $newNamespace);
  72883. }
  72884. }
  72885. private function calculateClassyName(\SplFileInfo $file, ?string $namespace, string $currentName): string
  72886. {
  72887. $name = $file->getBasename('.php');
  72888. $maxNamespace = $this->calculateMaxNamespace($file, $namespace);
  72889. if (null !== $this->configuration['dir']) {
  72890. return ('' !== $maxNamespace ? (str_replace('\\', '_', $maxNamespace).'_') : '').$name;
  72891. }
  72892. $namespaceParts = array_reverse(explode('\\', $maxNamespace));
  72893. foreach ($namespaceParts as $namespacePart) {
  72894. $nameCandidate = \sprintf('%s_%s', $namespacePart, $name);
  72895. if (strtolower($nameCandidate) !== strtolower(substr($currentName, -\strlen($nameCandidate)))) {
  72896. break;
  72897. }
  72898. $name = $nameCandidate;
  72899. }
  72900. return $name;
  72901. }
  72902. private function calculateMaxNamespace(\SplFileInfo $file, ?string $namespace): string
  72903. {
  72904. if (null === $this->configuration['dir']) {
  72905. $root = \dirname($file->getRealPath());
  72906. while ($root !== \dirname($root)) {
  72907. $root = \dirname($root);
  72908. }
  72909. } else {
  72910. $root = realpath($this->configuration['dir']);
  72911. }
  72912. $namespaceAccordingToFileLocation = trim(str_replace(\DIRECTORY_SEPARATOR, '\\', substr(\dirname($file->getRealPath()), \strlen($root))), '\\');
  72913. if (null === $namespace) {
  72914. return $namespaceAccordingToFileLocation;
  72915. }
  72916. $namespaceAccordingToFileLocationPartsReversed = array_reverse(explode('\\', $namespaceAccordingToFileLocation));
  72917. $namespacePartsReversed = array_reverse(explode('\\', $namespace));
  72918. foreach ($namespacePartsReversed as $key => $namespaceParte) {
  72919. if (!isset($namespaceAccordingToFileLocationPartsReversed[$key])) {
  72920. break;
  72921. }
  72922. if (strtolower($namespaceParte) !== strtolower($namespaceAccordingToFileLocationPartsReversed[$key])) {
  72923. break;
  72924. }
  72925. unset($namespaceAccordingToFileLocationPartsReversed[$key]);
  72926. }
  72927. return implode('\\', array_reverse($namespaceAccordingToFileLocationPartsReversed));
  72928. }
  72929. }
  72930. <?php
  72931. declare(strict_types=1);
  72932. namespace PhpCsFixer\Fixer\Basic;
  72933. use PhpCsFixer\AbstractFixer;
  72934. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  72935. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  72936. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  72937. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  72938. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  72939. use PhpCsFixer\FixerDefinition\CodeSample;
  72940. use PhpCsFixer\FixerDefinition\FixerDefinition;
  72941. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  72942. use PhpCsFixer\Preg;
  72943. use PhpCsFixer\Tokenizer\Token;
  72944. use PhpCsFixer\Tokenizer\Tokens;
  72945. /**
  72946. @phpstan-type
  72947. @phpstan-type
  72948. @implements
  72949. */
  72950. final class NumericLiteralSeparatorFixer extends AbstractFixer implements ConfigurableFixerInterface
  72951. {
  72952. /**
  72953. @use */
  72954. use ConfigurableFixerTrait;
  72955. public const STRATEGY_USE_SEPARATOR = 'use_separator';
  72956. public const STRATEGY_NO_SEPARATOR = 'no_separator';
  72957. public function getDefinition(): FixerDefinitionInterface
  72958. {
  72959. return new FixerDefinition(
  72960. 'Adds separators to numeric literals of any kind.',
  72961. [
  72962. new CodeSample(
  72963. <<<'PHP'
  72964. <?php
  72965. $integer = 1234567890;
  72966. PHP
  72967. ,
  72968. ),
  72969. new CodeSample(
  72970. <<<'PHP'
  72971. <?php
  72972. $integer = 1234_5678;
  72973. $octal = 01_234_56;
  72974. $binary = 0b00_10_01_00;
  72975. $hexadecimal = 0x3D45_8F4F;
  72976. PHP
  72977. ,
  72978. ['strategy' => self::STRATEGY_NO_SEPARATOR],
  72979. ),
  72980. new CodeSample(
  72981. <<<'PHP'
  72982. <?php
  72983. $integer = 12345678;
  72984. $octal = 0123456;
  72985. $binary = 0b0010010011011010;
  72986. $hexadecimal = 0x3D458F4F;
  72987. PHP
  72988. ,
  72989. ['strategy' => self::STRATEGY_USE_SEPARATOR],
  72990. ),
  72991. new CodeSample(
  72992. "<?php \$var = 24_40_21;\n",
  72993. ['override_existing' => true]
  72994. ),
  72995. ]
  72996. );
  72997. }
  72998. public function isCandidate(Tokens $tokens): bool
  72999. {
  73000. return $tokens->isAnyTokenKindsFound([T_DNUMBER, T_LNUMBER]);
  73001. }
  73002. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  73003. {
  73004. return new FixerConfigurationResolver([
  73005. (new FixerOptionBuilder(
  73006. 'override_existing',
  73007. 'Whether literals already containing underscores should be reformatted.'
  73008. ))
  73009. ->setAllowedTypes(['bool'])
  73010. ->setDefault(false)
  73011. ->getOption(),
  73012. (new FixerOptionBuilder(
  73013. 'strategy',
  73014. 'Whether numeric literal should be separated by underscores or not.'
  73015. ))
  73016. ->setAllowedValues([self::STRATEGY_USE_SEPARATOR, self::STRATEGY_NO_SEPARATOR])
  73017. ->setDefault(self::STRATEGY_USE_SEPARATOR)
  73018. ->getOption(),
  73019. ]);
  73020. }
  73021. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73022. {
  73023. foreach ($tokens as $index => $token) {
  73024. if (!$token->isGivenKind([T_DNUMBER, T_LNUMBER])) {
  73025. continue;
  73026. }
  73027. $content = $token->getContent();
  73028. $newContent = $this->formatValue($content);
  73029. if ($content === $newContent) {
  73030. continue;
  73031. }
  73032. $tokens[$index] = new Token([$token->getId(), $newContent]);
  73033. }
  73034. }
  73035. private function formatValue(string $value): string
  73036. {
  73037. if (self::STRATEGY_NO_SEPARATOR === $this->configuration['strategy']) {
  73038. return str_contains($value, '_') ? str_replace('_', '', $value) : $value;
  73039. }
  73040. if (true === $this->configuration['override_existing']) {
  73041. $value = str_replace('_', '', $value);
  73042. } elseif (str_contains($value, '_')) {
  73043. return $value;
  73044. }
  73045. $lowerValue = strtolower($value);
  73046. if (str_starts_with($lowerValue, '0b')) {
  73047. return $this->insertEveryRight($value, 8, 2);
  73048. }
  73049. if (str_starts_with($lowerValue, '0x')) {
  73050. return $this->insertEveryRight($value, 2, 2);
  73051. }
  73052. if (str_starts_with($lowerValue, '0o')) {
  73053. return $this->insertEveryRight($value, 3, 2);
  73054. }
  73055. if (str_starts_with($lowerValue, '0') && !str_contains($lowerValue, '.')) {
  73056. return $this->insertEveryRight($value, 3, 1);
  73057. }
  73058. $negativeOffset = static fn ($v) => str_contains($v, '-') ? 1 : 0;
  73059. Preg::matchAll('/([0-9-_]+)?((\.)([0-9_]*))?((e)([0-9-_]+))?/i', $value, $result);
  73060. $integer = $result[1][0];
  73061. $joinedValue = $this->insertEveryRight($integer, 3, $negativeOffset($integer));
  73062. $dot = $result[3][0];
  73063. if ('' !== $dot) {
  73064. $integer = $result[4][0];
  73065. $decimal = $this->insertEveryLeft($integer, 3, $negativeOffset($integer));
  73066. $joinedValue = $joinedValue.$dot.$decimal;
  73067. }
  73068. $tim = $result[6][0];
  73069. if ('' !== $tim) {
  73070. $integer = $result[7][0];
  73071. $times = $this->insertEveryRight($integer, 3, $negativeOffset($integer));
  73072. $joinedValue = $joinedValue.$tim.$times;
  73073. }
  73074. return $joinedValue;
  73075. }
  73076. private function insertEveryRight(string $value, int $length, int $offset = 0): string
  73077. {
  73078. $position = $length * -1;
  73079. while ($position > -(\strlen($value) - $offset)) {
  73080. $value = substr_replace($value, '_', $position, 0);
  73081. $position -= $length + 1;
  73082. }
  73083. return $value;
  73084. }
  73085. private function insertEveryLeft(string $value, int $length, int $offset = 0): string
  73086. {
  73087. $position = $length;
  73088. while ($position < \strlen($value)) {
  73089. $value = substr_replace($value, '_', $position, $offset);
  73090. $position += $length + 1;
  73091. }
  73092. return $value;
  73093. }
  73094. }
  73095. <?php
  73096. declare(strict_types=1);
  73097. namespace PhpCsFixer\Fixer\Basic;
  73098. use PhpCsFixer\AbstractFixer;
  73099. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73100. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73101. use PhpCsFixer\FixerDefinition\VersionSpecification;
  73102. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  73103. use PhpCsFixer\Preg;
  73104. use PhpCsFixer\Tokenizer\Token;
  73105. use PhpCsFixer\Tokenizer\Tokens;
  73106. final class OctalNotationFixer extends AbstractFixer
  73107. {
  73108. public function getDefinition(): FixerDefinitionInterface
  73109. {
  73110. return new FixerDefinition(
  73111. 'Literal octal must be in `0o` notation.',
  73112. [
  73113. new VersionSpecificCodeSample(
  73114. "<?php \$foo = 0123;\n",
  73115. new VersionSpecification(8_01_00)
  73116. ),
  73117. ]
  73118. );
  73119. }
  73120. public function isCandidate(Tokens $tokens): bool
  73121. {
  73122. return \PHP_VERSION_ID >= 8_01_00 && $tokens->isTokenKindFound(T_LNUMBER);
  73123. }
  73124. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73125. {
  73126. foreach ($tokens as $index => $token) {
  73127. if (!$token->isGivenKind(T_LNUMBER)) {
  73128. continue;
  73129. }
  73130. $content = $token->getContent();
  73131. $newContent = Preg::replace('#^0_*+([0-7_]+)$#', '0o$1', $content);
  73132. if ($content === $newContent) {
  73133. continue;
  73134. }
  73135. $tokens[$index] = new Token([T_LNUMBER, $newContent]);
  73136. }
  73137. }
  73138. }
  73139. <?php
  73140. declare(strict_types=1);
  73141. namespace PhpCsFixer\Fixer\Basic;
  73142. use PhpCsFixer\AbstractFixer;
  73143. use PhpCsFixer\Fixer\Indentation;
  73144. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  73145. use PhpCsFixer\FixerDefinition\CodeSample;
  73146. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73147. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73148. use PhpCsFixer\Preg;
  73149. use PhpCsFixer\Tokenizer\CT;
  73150. use PhpCsFixer\Tokenizer\Tokens;
  73151. final class NoMultipleStatementsPerLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  73152. {
  73153. use Indentation;
  73154. public function getDefinition(): FixerDefinitionInterface
  73155. {
  73156. return new FixerDefinition(
  73157. 'There must not be more than one statement per line.',
  73158. [new CodeSample("<?php\nfoo(); bar();\n")]
  73159. );
  73160. }
  73161. public function getPriority(): int
  73162. {
  73163. return -1;
  73164. }
  73165. public function isCandidate(Tokens $tokens): bool
  73166. {
  73167. return $tokens->isTokenKindFound(';');
  73168. }
  73169. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73170. {
  73171. for ($index = 1, $max = \count($tokens) - 1; $index < $max; ++$index) {
  73172. if ($tokens[$index]->isGivenKind(T_FOR)) {
  73173. $index = $tokens->findBlockEnd(
  73174. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  73175. $tokens->getNextTokenOfKind($index, ['('])
  73176. );
  73177. continue;
  73178. }
  73179. if ($tokens[$index]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
  73180. $index = $tokens->findBlockEnd(
  73181. Tokens::BLOCK_TYPE_PROPERTY_HOOK,
  73182. $index
  73183. );
  73184. continue;
  73185. }
  73186. if (!$tokens[$index]->equals(';')) {
  73187. continue;
  73188. }
  73189. for ($nextIndex = $index + 1; $nextIndex < $max; ++$nextIndex) {
  73190. $token = $tokens[$nextIndex];
  73191. if ($token->isWhitespace() || $token->isComment()) {
  73192. if (Preg::match('/\R/', $token->getContent())) {
  73193. break;
  73194. }
  73195. continue;
  73196. }
  73197. if (!$token->equalsAny(['}', [T_CLOSE_TAG], [T_ENDIF], [T_ENDFOR], [T_ENDSWITCH], [T_ENDWHILE], [T_ENDFOREACH]])) {
  73198. $whitespaceIndex = $index;
  73199. do {
  73200. $token = $tokens[++$whitespaceIndex];
  73201. } while ($token->isComment());
  73202. $newline = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
  73203. if ($tokens->ensureWhitespaceAtIndex($whitespaceIndex, 0, $newline)) {
  73204. ++$max;
  73205. }
  73206. }
  73207. break;
  73208. }
  73209. }
  73210. }
  73211. }
  73212. <?php
  73213. declare(strict_types=1);
  73214. namespace PhpCsFixer\Fixer;
  73215. use PhpCsFixer\WhitespacesFixerConfig;
  73216. interface WhitespacesAwareFixerInterface extends FixerInterface
  73217. {
  73218. public function setWhitespacesConfig(WhitespacesFixerConfig $config): void;
  73219. }
  73220. <?php
  73221. declare(strict_types=1);
  73222. namespace PhpCsFixer\Fixer\StringNotation;
  73223. use PhpCsFixer\AbstractFixer;
  73224. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  73225. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  73226. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  73227. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  73228. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  73229. use PhpCsFixer\FixerDefinition\CodeSample;
  73230. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73231. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73232. use PhpCsFixer\Preg;
  73233. use PhpCsFixer\Tokenizer\Token;
  73234. use PhpCsFixer\Tokenizer\Tokens;
  73235. /**
  73236. @phpstan-type
  73237. @phpstan-type
  73238. @implements
  73239. */
  73240. final class HeredocClosingMarkerFixer extends AbstractFixer implements ConfigurableFixerInterface
  73241. {
  73242. /**
  73243. @use */
  73244. use ConfigurableFixerTrait;
  73245. public const RESERVED_CLOSING_MARKERS = [
  73246. 'CSS',
  73247. 'DIFF',
  73248. 'HTML',
  73249. 'JS',
  73250. 'JSON',
  73251. 'MD',
  73252. 'PHP',
  73253. 'PYTHON',
  73254. 'RST',
  73255. 'TS',
  73256. 'SQL',
  73257. 'XML',
  73258. 'YAML',
  73259. ];
  73260. public function getDefinition(): FixerDefinitionInterface
  73261. {
  73262. return new FixerDefinition(
  73263. 'Unify `heredoc` or `nowdoc` closing marker.',
  73264. [
  73265. new CodeSample(
  73266. <<<'EOD'
  73267. <?php $a = <<<"TEST"
  73268. Foo
  73269. TEST;
  73270. EOD
  73271. ),
  73272. new CodeSample(
  73273. <<<'EOD'
  73274. <?php $a = <<<'TEST'
  73275. Foo
  73276. TEST;
  73277. EOD,
  73278. ['closing_marker' => 'EOF']
  73279. ),
  73280. new CodeSample(
  73281. <<<'EOD_'
  73282. <?php $a = <<<EOD
  73283. Foo
  73284. EOD;
  73285. EOD_,
  73286. ['explicit_heredoc_style' => true]
  73287. ),
  73288. ]
  73289. );
  73290. }
  73291. public function isCandidate(Tokens $tokens): bool
  73292. {
  73293. return $tokens->isTokenKindFound(T_START_HEREDOC);
  73294. }
  73295. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  73296. {
  73297. return new FixerConfigurationResolver([
  73298. (new FixerOptionBuilder(
  73299. 'closing_marker',
  73300. 'Preferred closing marker.'
  73301. ))
  73302. ->setAllowedTypes(['string'])
  73303. ->setDefault('EOD')
  73304. ->getOption(),
  73305. (new FixerOptionBuilder(
  73306. 'reserved_closing_markers',
  73307. 'Reserved closing markers to be kept unchanged.'
  73308. ))
  73309. ->setAllowedTypes(['string[]'])
  73310. ->setDefault(self::RESERVED_CLOSING_MARKERS)
  73311. ->getOption(),
  73312. (new FixerOptionBuilder(
  73313. 'explicit_heredoc_style',
  73314. 'Whether the closing marker should be wrapped in double quotes.'
  73315. ))
  73316. ->setAllowedTypes(['bool'])
  73317. ->setDefault(false)
  73318. ->getOption(),
  73319. ]);
  73320. }
  73321. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73322. {
  73323. $reservedClosingMarkersMap = null;
  73324. $startIndex = null;
  73325. foreach ($tokens as $index => $token) {
  73326. if ($token->isGivenKind(T_START_HEREDOC)) {
  73327. $startIndex = $index;
  73328. continue;
  73329. }
  73330. if (null !== $startIndex && $token->isGivenKind(T_END_HEREDOC)) {
  73331. $existingClosingMarker = trim($token->getContent());
  73332. if (null === $reservedClosingMarkersMap) {
  73333. $reservedClosingMarkersMap = [];
  73334. foreach ($this->configuration['reserved_closing_markers'] as $v) {
  73335. $reservedClosingMarkersMap[mb_strtoupper($v)] = $v;
  73336. }
  73337. }
  73338. $existingClosingMarker = mb_strtoupper($existingClosingMarker);
  73339. do {
  73340. $newClosingMarker = $reservedClosingMarkersMap[$existingClosingMarker] ?? null;
  73341. if (!str_ends_with($existingClosingMarker, '_')) {
  73342. break;
  73343. }
  73344. $existingClosingMarker = substr($existingClosingMarker, 0, -1);
  73345. } while (null === $newClosingMarker);
  73346. if (null === $newClosingMarker) {
  73347. $newClosingMarker = $this->configuration['closing_marker'];
  73348. }
  73349. $content = $tokens->generatePartialCode($startIndex + 1, $index - 1);
  73350. while (Preg::match('~(^|[\r\n])\s*'.preg_quote($newClosingMarker, '~').'(?!\w)~', $content)) {
  73351. $newClosingMarker .= '_';
  73352. }
  73353. [$tokens[$startIndex], $tokens[$index]] = $this->convertClosingMarker($tokens[$startIndex], $token, $newClosingMarker);
  73354. $startIndex = null;
  73355. continue;
  73356. }
  73357. }
  73358. }
  73359. private function convertClosingMarker(Token $startToken, Token $endToken, string $newClosingMarker): array
  73360. {
  73361. $isNowdoc = str_contains($startToken->getContent(), '\'');
  73362. $markerQuote = $isNowdoc
  73363. ? '\''
  73364. : (true === $this->configuration['explicit_heredoc_style'] ? '"' : '');
  73365. return [new Token([
  73366. $startToken->getId(),
  73367. Preg::replace('/<<<\h*\K["\']?[^\s"\']+["\']?/', $markerQuote.$newClosingMarker.$markerQuote, $startToken->getContent()),
  73368. ]), new Token([
  73369. $endToken->getId(),
  73370. Preg::replace('/\S+/', $newClosingMarker, $endToken->getContent()),
  73371. ])];
  73372. }
  73373. }
  73374. <?php
  73375. declare(strict_types=1);
  73376. namespace PhpCsFixer\Fixer\StringNotation;
  73377. use PhpCsFixer\AbstractFixer;
  73378. use PhpCsFixer\FixerDefinition\CodeSample;
  73379. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73380. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73381. use PhpCsFixer\Preg;
  73382. use PhpCsFixer\Tokenizer\Token;
  73383. use PhpCsFixer\Tokenizer\Tokens;
  73384. final class NoTrailingWhitespaceInStringFixer extends AbstractFixer
  73385. {
  73386. public function isCandidate(Tokens $tokens): bool
  73387. {
  73388. return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML]);
  73389. }
  73390. public function isRisky(): bool
  73391. {
  73392. return true;
  73393. }
  73394. public function getDefinition(): FixerDefinitionInterface
  73395. {
  73396. return new FixerDefinition(
  73397. 'There must be no trailing whitespace in strings.',
  73398. [
  73399. new CodeSample(
  73400. "<?php \$a = ' \n foo \n';\n"
  73401. ),
  73402. ],
  73403. null,
  73404. 'Changing the whitespaces in strings might affect string comparisons and outputs.'
  73405. );
  73406. }
  73407. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73408. {
  73409. for ($index = $tokens->count() - 1, $last = true; $index >= 0; --$index, $last = false) {
  73410. $token = $tokens[$index];
  73411. if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML])) {
  73412. continue;
  73413. }
  73414. $isInlineHtml = $token->isGivenKind(T_INLINE_HTML);
  73415. $regex = $isInlineHtml && $last ? '/\h+(?=\R|$)/' : '/\h+(?=\R)/';
  73416. $content = Preg::replace($regex, '', $token->getContent());
  73417. if ($token->getContent() === $content) {
  73418. continue;
  73419. }
  73420. if (!$isInlineHtml || 0 === $index) {
  73421. $this->updateContent($tokens, $index, $content);
  73422. continue;
  73423. }
  73424. $prev = $index - 1;
  73425. if ($tokens[$prev]->equals([T_CLOSE_TAG, '?>']) && Preg::match('/^\R/', $content, $match)) {
  73426. $tokens[$prev] = new Token([T_CLOSE_TAG, $tokens[$prev]->getContent().$match[0]]);
  73427. $content = substr($content, \strlen($match[0]));
  73428. $content = false === $content ? '' : $content;
  73429. }
  73430. $this->updateContent($tokens, $index, $content);
  73431. }
  73432. }
  73433. private function updateContent(Tokens $tokens, int $index, string $content): void
  73434. {
  73435. if ('' === $content) {
  73436. $tokens->clearAt($index);
  73437. return;
  73438. }
  73439. $tokens[$index] = new Token([$tokens[$index]->getId(), $content]);
  73440. }
  73441. }
  73442. <?php
  73443. declare(strict_types=1);
  73444. namespace PhpCsFixer\Fixer\StringNotation;
  73445. use PhpCsFixer\AbstractFixer;
  73446. use PhpCsFixer\FixerDefinition\CodeSample;
  73447. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73448. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73449. use PhpCsFixer\Tokenizer\CT;
  73450. use PhpCsFixer\Tokenizer\Token;
  73451. use PhpCsFixer\Tokenizer\Tokens;
  73452. final class SimpleToComplexStringVariableFixer extends AbstractFixer
  73453. {
  73454. public function getDefinition(): FixerDefinitionInterface
  73455. {
  73456. return new FixerDefinition(
  73457. 'Converts explicit variables in double-quoted strings and heredoc syntax from simple to complex format (`${` to `{$`).',
  73458. [
  73459. new CodeSample(
  73460. <<<'EOT'
  73461. <?php
  73462. $name = 'World';
  73463. echo "Hello ${name}!";
  73464. EOT
  73465. ),
  73466. new CodeSample(
  73467. <<<'EOT'
  73468. <?php
  73469. $name = 'World';
  73470. echo <<<TEST
  73471. Hello ${name}!
  73472. TEST;
  73473. EOT
  73474. ),
  73475. ],
  73476. "Doesn't touch implicit variables. Works together nicely with `explicit_string_variable`."
  73477. );
  73478. }
  73479. public function getPriority(): int
  73480. {
  73481. return -10;
  73482. }
  73483. public function isCandidate(Tokens $tokens): bool
  73484. {
  73485. return $tokens->isTokenKindFound(T_DOLLAR_OPEN_CURLY_BRACES);
  73486. }
  73487. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73488. {
  73489. for ($index = \count($tokens) - 3; $index > 0; --$index) {
  73490. if (!$tokens[$index]->isGivenKind(T_DOLLAR_OPEN_CURLY_BRACES)) {
  73491. continue;
  73492. }
  73493. $varnameToken = $tokens[$index + 1];
  73494. if (!$varnameToken->isGivenKind(T_STRING_VARNAME)) {
  73495. continue;
  73496. }
  73497. $dollarCloseToken = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_COMPLEX_STRING_VARIABLE, $index);
  73498. $prevTokenContent = $tokens[$index - 1]->getContent();
  73499. if (str_ends_with($prevTokenContent, '$') && !str_ends_with($prevTokenContent, '\$')) {
  73500. $tokens[$index - 1] = new Token([T_ENCAPSED_AND_WHITESPACE, substr($prevTokenContent, 0, -1).'\$']);
  73501. }
  73502. $tokens[$index] = new Token([T_CURLY_OPEN, '{']);
  73503. $tokens[$index + 1] = new Token([T_VARIABLE, '$'.$varnameToken->getContent()]);
  73504. $tokens[$dollarCloseToken] = new Token([CT::T_CURLY_CLOSE, '}']);
  73505. }
  73506. }
  73507. }
  73508. <?php
  73509. declare(strict_types=1);
  73510. namespace PhpCsFixer\Fixer\StringNotation;
  73511. use PhpCsFixer\AbstractFixer;
  73512. use PhpCsFixer\FixerDefinition\CodeSample;
  73513. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73514. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73515. use PhpCsFixer\Tokenizer\Token;
  73516. use PhpCsFixer\Tokenizer\Tokens;
  73517. final class NoBinaryStringFixer extends AbstractFixer
  73518. {
  73519. public function isCandidate(Tokens $tokens): bool
  73520. {
  73521. return $tokens->isAnyTokenKindsFound(
  73522. [
  73523. T_CONSTANT_ENCAPSED_STRING,
  73524. T_START_HEREDOC,
  73525. 'b"',
  73526. ]
  73527. );
  73528. }
  73529. public function getDefinition(): FixerDefinitionInterface
  73530. {
  73531. return new FixerDefinition(
  73532. 'There should not be a binary flag before strings.',
  73533. [
  73534. new CodeSample("<?php \$a = b'foo';\n"),
  73535. new CodeSample("<?php \$a = b<<<EOT\nfoo\nEOT;\n"),
  73536. ]
  73537. );
  73538. }
  73539. public function getPriority(): int
  73540. {
  73541. return 40;
  73542. }
  73543. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73544. {
  73545. foreach ($tokens as $index => $token) {
  73546. if ($token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_START_HEREDOC])) {
  73547. $content = $token->getContent();
  73548. if ('b' === strtolower($content[0])) {
  73549. $tokens[$index] = new Token([$token->getId(), substr($content, 1)]);
  73550. }
  73551. } elseif ($token->equals('b"')) {
  73552. $tokens[$index] = new Token('"');
  73553. }
  73554. }
  73555. }
  73556. }
  73557. <?php
  73558. declare(strict_types=1);
  73559. namespace PhpCsFixer\Fixer\StringNotation;
  73560. use PhpCsFixer\AbstractFixer;
  73561. use PhpCsFixer\FixerDefinition\CodeSample;
  73562. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73563. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73564. use PhpCsFixer\Tokenizer\CT;
  73565. use PhpCsFixer\Tokenizer\Token;
  73566. use PhpCsFixer\Tokenizer\Tokens;
  73567. final class ExplicitStringVariableFixer extends AbstractFixer
  73568. {
  73569. public function getDefinition(): FixerDefinitionInterface
  73570. {
  73571. return new FixerDefinition(
  73572. 'Converts implicit variables into explicit ones in double-quoted strings or heredoc syntax.',
  73573. [new CodeSample(
  73574. <<<'EOT'
  73575. <?php
  73576. $a = "My name is $name !";
  73577. $b = "I live in $state->country !";
  73578. $c = "I have $farm[0] chickens !";
  73579. EOT
  73580. )],
  73581. 'The reasoning behind this rule is the following:'
  73582. ."\n".'- When there are two valid ways of doing the same thing, using both is confusing, there should be a coding standard to follow.'
  73583. ."\n".'- PHP manual marks `"$var"` syntax as implicit and `"{$var}"` syntax as explicit: explicit code should always be preferred.'
  73584. ."\n".'- Explicit syntax allows word concatenation inside strings, e.g. `"{$var}IsAVar"`, implicit doesn\'t.'
  73585. ."\n".'- Explicit syntax is easier to detect for IDE/editors and therefore has colors/highlight with higher contrast, which is easier to read.'
  73586. ."\n".'Backtick operator is skipped because it is harder to handle; you can use `backtick_to_shell_exec` fixer to normalize backticks to strings.'
  73587. );
  73588. }
  73589. public function getPriority(): int
  73590. {
  73591. return 6;
  73592. }
  73593. public function isCandidate(Tokens $tokens): bool
  73594. {
  73595. return $tokens->isTokenKindFound(T_VARIABLE);
  73596. }
  73597. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73598. {
  73599. $backtickStarted = false;
  73600. for ($index = \count($tokens) - 1; $index > 0; --$index) {
  73601. $token = $tokens[$index];
  73602. if ($token->equals('`')) {
  73603. $backtickStarted = !$backtickStarted;
  73604. continue;
  73605. }
  73606. if ($backtickStarted || !$token->isGivenKind(T_VARIABLE)) {
  73607. continue;
  73608. }
  73609. $prevToken = $tokens[$index - 1];
  73610. if (!$this->isStringPartToken($prevToken)) {
  73611. continue;
  73612. }
  73613. $distinctVariableIndex = $index;
  73614. $variableTokens = [
  73615. $distinctVariableIndex => [
  73616. 'tokens' => [$index => $token],
  73617. 'firstVariableTokenIndex' => $index,
  73618. 'lastVariableTokenIndex' => $index,
  73619. ],
  73620. ];
  73621. $nextIndex = $index + 1;
  73622. $squareBracketCount = 0;
  73623. while (!$this->isStringPartToken($tokens[$nextIndex])) {
  73624. if ($tokens[$nextIndex]->isGivenKind(T_CURLY_OPEN)) {
  73625. $nextIndex = $tokens->getNextTokenOfKind($nextIndex, [[CT::T_CURLY_CLOSE]]);
  73626. } elseif ($tokens[$nextIndex]->isGivenKind(T_VARIABLE) && 1 !== $squareBracketCount) {
  73627. $distinctVariableIndex = $nextIndex;
  73628. $variableTokens[$distinctVariableIndex] = [
  73629. 'tokens' => [$nextIndex => $tokens[$nextIndex]],
  73630. 'firstVariableTokenIndex' => $nextIndex,
  73631. 'lastVariableTokenIndex' => $nextIndex,
  73632. ];
  73633. } else {
  73634. $variableTokens[$distinctVariableIndex]['tokens'][$nextIndex] = $tokens[$nextIndex];
  73635. $variableTokens[$distinctVariableIndex]['lastVariableTokenIndex'] = $nextIndex;
  73636. if ($tokens[$nextIndex]->equalsAny(['[', ']'])) {
  73637. ++$squareBracketCount;
  73638. }
  73639. }
  73640. ++$nextIndex;
  73641. }
  73642. krsort($variableTokens, SORT_NUMERIC);
  73643. foreach ($variableTokens as $distinctVariableSet) {
  73644. if (1 === \count($distinctVariableSet['tokens'])) {
  73645. $singleVariableIndex = array_key_first($distinctVariableSet['tokens']);
  73646. $singleVariableToken = current($distinctVariableSet['tokens']);
  73647. $tokens->overrideRange($singleVariableIndex, $singleVariableIndex, [
  73648. new Token([T_CURLY_OPEN, '{']),
  73649. new Token([T_VARIABLE, $singleVariableToken->getContent()]),
  73650. new Token([CT::T_CURLY_CLOSE, '}']),
  73651. ]);
  73652. } else {
  73653. foreach ($distinctVariableSet['tokens'] as $variablePartIndex => $variablePartToken) {
  73654. if ($variablePartToken->isGivenKind(T_NUM_STRING)) {
  73655. $tokens[$variablePartIndex] = new Token([T_LNUMBER, $variablePartToken->getContent()]);
  73656. continue;
  73657. }
  73658. if ($variablePartToken->isGivenKind(T_STRING) && $tokens[$variablePartIndex + 1]->equals(']')) {
  73659. $tokens[$variablePartIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, "'".$variablePartToken->getContent()."'"]);
  73660. }
  73661. }
  73662. $tokens->insertAt($distinctVariableSet['lastVariableTokenIndex'] + 1, new Token([CT::T_CURLY_CLOSE, '}']));
  73663. $tokens->insertAt($distinctVariableSet['firstVariableTokenIndex'], new Token([T_CURLY_OPEN, '{']));
  73664. }
  73665. }
  73666. }
  73667. }
  73668. private function isStringPartToken(Token $token): bool
  73669. {
  73670. return $token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)
  73671. || $token->isGivenKind(T_START_HEREDOC)
  73672. || '"' === $token->getContent()
  73673. || 'b"' === strtolower($token->getContent());
  73674. }
  73675. }
  73676. <?php
  73677. declare(strict_types=1);
  73678. namespace PhpCsFixer\Fixer\StringNotation;
  73679. use PhpCsFixer\AbstractFixer;
  73680. use PhpCsFixer\FixerDefinition\CodeSample;
  73681. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73682. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73683. use PhpCsFixer\Preg;
  73684. use PhpCsFixer\Tokenizer\Token;
  73685. use PhpCsFixer\Tokenizer\Tokens;
  73686. final class HeredocToNowdocFixer extends AbstractFixer
  73687. {
  73688. public function getDefinition(): FixerDefinitionInterface
  73689. {
  73690. return new FixerDefinition(
  73691. 'Convert `heredoc` to `nowdoc` where possible.',
  73692. [
  73693. new CodeSample(
  73694. <<<'EOF'
  73695. <?php $a = <<<"TEST"
  73696. Foo
  73697. TEST;
  73698. EOF
  73699. ),
  73700. ]
  73701. );
  73702. }
  73703. public function getPriority(): int
  73704. {
  73705. return 0;
  73706. }
  73707. public function isCandidate(Tokens $tokens): bool
  73708. {
  73709. return $tokens->isTokenKindFound(T_START_HEREDOC);
  73710. }
  73711. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73712. {
  73713. foreach ($tokens as $index => $token) {
  73714. if (!$token->isGivenKind(T_START_HEREDOC) || str_contains($token->getContent(), "'")) {
  73715. continue;
  73716. }
  73717. if ($tokens[$index + 1]->isGivenKind(T_END_HEREDOC)) {
  73718. $tokens[$index] = $this->convertToNowdoc($token);
  73719. continue;
  73720. }
  73721. if (
  73722. !$tokens[$index + 1]->isGivenKind(T_ENCAPSED_AND_WHITESPACE)
  73723. || !$tokens[$index + 2]->isGivenKind(T_END_HEREDOC)
  73724. ) {
  73725. continue;
  73726. }
  73727. $content = $tokens[$index + 1]->getContent();
  73728. if (Preg::match('/(?<!\\\)(?:\\\{2})*\\\(?![$\\\])/', $content)) {
  73729. continue;
  73730. }
  73731. $tokens[$index] = $this->convertToNowdoc($token);
  73732. $content = str_replace(['\\\\', '\$'], ['\\', '$'], $content);
  73733. $tokens[$index + 1] = new Token([
  73734. $tokens[$index + 1]->getId(),
  73735. $content,
  73736. ]);
  73737. }
  73738. }
  73739. private function convertToNowdoc(Token $token): Token
  73740. {
  73741. return new Token([
  73742. $token->getId(),
  73743. Preg::replace('/^([Bb]?<<<)(\h*)"?([^\s"]+)"?/', '$1$2\'$3\'', $token->getContent()),
  73744. ]);
  73745. }
  73746. }
  73747. <?php
  73748. declare(strict_types=1);
  73749. namespace PhpCsFixer\Fixer\StringNotation;
  73750. use PhpCsFixer\AbstractFunctionReferenceFixer;
  73751. use PhpCsFixer\FixerDefinition\CodeSample;
  73752. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73753. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73754. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  73755. use PhpCsFixer\Tokenizer\Token;
  73756. use PhpCsFixer\Tokenizer\Tokens;
  73757. final class StringLengthToEmptyFixer extends AbstractFunctionReferenceFixer
  73758. {
  73759. public function getDefinition(): FixerDefinitionInterface
  73760. {
  73761. return new FixerDefinition(
  73762. 'String tests for empty must be done against `\'\'`, not with `strlen`.',
  73763. [new CodeSample("<?php \$a = 0 === strlen(\$b) || \\STRLEN(\$c) < 1;\n")],
  73764. null,
  73765. 'Risky when `strlen` is overridden, when called using a `stringable` object, also no longer triggers warning when called using non-string(able).'
  73766. );
  73767. }
  73768. public function getPriority(): int
  73769. {
  73770. return 1;
  73771. }
  73772. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73773. {
  73774. $argumentsAnalyzer = new ArgumentsAnalyzer();
  73775. foreach ($this->findStrLengthCalls($tokens) as $candidate) {
  73776. [$functionNameIndex, $openParenthesisIndex, $closeParenthesisIndex] = $candidate;
  73777. $arguments = $argumentsAnalyzer->getArguments($tokens, $openParenthesisIndex, $closeParenthesisIndex);
  73778. if (1 !== \count($arguments)) {
  73779. continue;
  73780. }
  73781. $nextIndex = $tokens->getNextMeaningfulToken($closeParenthesisIndex);
  73782. $previousIndex = $tokens->getPrevMeaningfulToken($functionNameIndex);
  73783. if ($tokens[$previousIndex]->isGivenKind(T_NS_SEPARATOR)) {
  73784. $namespaceSeparatorIndex = $previousIndex;
  73785. $previousIndex = $tokens->getPrevMeaningfulToken($previousIndex);
  73786. } else {
  73787. $namespaceSeparatorIndex = null;
  73788. }
  73789. if ($this->isOperatorOfInterest($tokens[$previousIndex])) {
  73790. $operatorIndex = $previousIndex;
  73791. $operandIndex = $tokens->getPrevMeaningfulToken($previousIndex);
  73792. if (!$this->isOperandOfInterest($tokens[$operandIndex])) {
  73793. continue;
  73794. }
  73795. $replacement = $this->getReplacementYoda($tokens[$operatorIndex], $tokens[$operandIndex]);
  73796. if (null === $replacement) {
  73797. continue;
  73798. }
  73799. if ($this->isOfHigherPrecedence($tokens[$nextIndex])) {
  73800. continue;
  73801. }
  73802. if ($this->isOfHigherPrecedence($tokens[$tokens->getPrevMeaningfulToken($operandIndex)])) {
  73803. continue;
  73804. }
  73805. } elseif ($this->isOperatorOfInterest($tokens[$nextIndex])) {
  73806. $operatorIndex = $nextIndex;
  73807. $operandIndex = $tokens->getNextMeaningfulToken($nextIndex);
  73808. if (!$this->isOperandOfInterest($tokens[$operandIndex])) {
  73809. continue;
  73810. }
  73811. $replacement = $this->getReplacementNotYoda($tokens[$operatorIndex], $tokens[$operandIndex]);
  73812. if (null === $replacement) {
  73813. continue;
  73814. }
  73815. if ($this->isOfHigherPrecedence($tokens[$tokens->getNextMeaningfulToken($operandIndex)])) {
  73816. continue;
  73817. }
  73818. if ($this->isOfHigherPrecedence($tokens[$previousIndex])) {
  73819. continue;
  73820. }
  73821. } else {
  73822. continue;
  73823. }
  73824. $keepParentheses = $this->keepParentheses($tokens, $openParenthesisIndex, $closeParenthesisIndex);
  73825. if (T_IS_IDENTICAL === $replacement) {
  73826. $operandContent = '===';
  73827. } else {
  73828. $operandContent = '!==';
  73829. }
  73830. $tokens[$operandIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, "''"]);
  73831. $tokens[$operatorIndex] = new Token([$replacement, $operandContent]);
  73832. if (!$keepParentheses) {
  73833. $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesisIndex);
  73834. $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesisIndex);
  73835. }
  73836. $tokens->clearTokenAndMergeSurroundingWhitespace($functionNameIndex);
  73837. if (null !== $namespaceSeparatorIndex) {
  73838. $tokens->clearTokenAndMergeSurroundingWhitespace($namespaceSeparatorIndex);
  73839. }
  73840. }
  73841. }
  73842. private function getReplacementYoda(Token $operator, Token $operand): ?int
  73843. {
  73844. if ('0' === $operand->getContent()) {
  73845. if ($operator->isGivenKind([T_IS_IDENTICAL, T_IS_GREATER_OR_EQUAL])) {
  73846. return T_IS_IDENTICAL;
  73847. }
  73848. if ($operator->isGivenKind(T_IS_NOT_IDENTICAL) || $operator->equals('<')) {
  73849. return T_IS_NOT_IDENTICAL;
  73850. }
  73851. return null;
  73852. }
  73853. if ($operator->isGivenKind(T_IS_SMALLER_OR_EQUAL)) {
  73854. return T_IS_NOT_IDENTICAL;
  73855. }
  73856. if ($operator->equals('>')) {
  73857. return T_IS_IDENTICAL;
  73858. }
  73859. return null;
  73860. }
  73861. private function getReplacementNotYoda(Token $operator, Token $operand): ?int
  73862. {
  73863. if ('0' === $operand->getContent()) {
  73864. if ($operator->isGivenKind([T_IS_IDENTICAL, T_IS_SMALLER_OR_EQUAL])) {
  73865. return T_IS_IDENTICAL;
  73866. }
  73867. if ($operator->isGivenKind(T_IS_NOT_IDENTICAL) || $operator->equals('>')) {
  73868. return T_IS_NOT_IDENTICAL;
  73869. }
  73870. return null;
  73871. }
  73872. if ($operator->isGivenKind(T_IS_GREATER_OR_EQUAL)) {
  73873. return T_IS_NOT_IDENTICAL;
  73874. }
  73875. if ($operator->equals('<')) {
  73876. return T_IS_IDENTICAL;
  73877. }
  73878. return null;
  73879. }
  73880. private function isOperandOfInterest(Token $token): bool
  73881. {
  73882. if (!$token->isGivenKind(T_LNUMBER)) {
  73883. return false;
  73884. }
  73885. $content = $token->getContent();
  73886. return '0' === $content || '1' === $content;
  73887. }
  73888. private function isOperatorOfInterest(Token $token): bool
  73889. {
  73890. return
  73891. $token->isGivenKind([T_IS_IDENTICAL, T_IS_NOT_IDENTICAL, T_IS_SMALLER_OR_EQUAL, T_IS_GREATER_OR_EQUAL])
  73892. || $token->equals('<') || $token->equals('>');
  73893. }
  73894. private function isOfHigherPrecedence(Token $token): bool
  73895. {
  73896. static $operatorsPerContent = [
  73897. '!',
  73898. '%',
  73899. '*',
  73900. '+',
  73901. '-',
  73902. '.',
  73903. '/',
  73904. '~',
  73905. '?',
  73906. ];
  73907. return $token->isGivenKind([T_INSTANCEOF, T_POW, T_SL, T_SR]) || $token->equalsAny($operatorsPerContent);
  73908. }
  73909. private function keepParentheses(Tokens $tokens, int $openParenthesisIndex, int $closeParenthesisIndex): bool
  73910. {
  73911. $i = $tokens->getNextMeaningfulToken($openParenthesisIndex);
  73912. if ($tokens[$i]->isCast()) {
  73913. $i = $tokens->getNextMeaningfulToken($i);
  73914. }
  73915. for (; $i < $closeParenthesisIndex; ++$i) {
  73916. $token = $tokens[$i];
  73917. if ($token->isGivenKind([T_VARIABLE, T_STRING]) || $token->isObjectOperator() || $token->isWhitespace() || $token->isComment()) {
  73918. continue;
  73919. }
  73920. $blockType = Tokens::detectBlockType($token);
  73921. if (null !== $blockType && $blockType['isStart']) {
  73922. $i = $tokens->findBlockEnd($blockType['type'], $i);
  73923. continue;
  73924. }
  73925. return true;
  73926. }
  73927. return false;
  73928. }
  73929. private function findStrLengthCalls(Tokens $tokens): \Generator
  73930. {
  73931. $candidates = [];
  73932. $count = \count($tokens);
  73933. for ($i = 0; $i < $count; ++$i) {
  73934. $candidate = $this->find('strlen', $tokens, $i, $count);
  73935. if (null === $candidate) {
  73936. break;
  73937. }
  73938. $i = $candidate[1];
  73939. $candidates[] = $candidate;
  73940. }
  73941. foreach (array_reverse($candidates) as $candidate) {
  73942. yield $candidate;
  73943. }
  73944. }
  73945. }
  73946. <?php
  73947. declare(strict_types=1);
  73948. namespace PhpCsFixer\Fixer\StringNotation;
  73949. use PhpCsFixer\AbstractFixer;
  73950. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  73951. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  73952. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  73953. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  73954. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  73955. use PhpCsFixer\FixerDefinition\CodeSample;
  73956. use PhpCsFixer\FixerDefinition\FixerDefinition;
  73957. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  73958. use PhpCsFixer\Preg;
  73959. use PhpCsFixer\Tokenizer\Token;
  73960. use PhpCsFixer\Tokenizer\Tokens;
  73961. /**
  73962. @phpstan-type
  73963. @phpstan-type
  73964. @implements
  73965. */
  73966. final class SingleQuoteFixer extends AbstractFixer implements ConfigurableFixerInterface
  73967. {
  73968. /**
  73969. @use */
  73970. use ConfigurableFixerTrait;
  73971. public function getDefinition(): FixerDefinitionInterface
  73972. {
  73973. $codeSample = <<<'EOF'
  73974. <?php
  73975. $a = "sample";
  73976. $b = "sample with 'single-quotes'";
  73977. EOF;
  73978. return new FixerDefinition(
  73979. 'Convert double quotes to single quotes for simple strings.',
  73980. [
  73981. new CodeSample($codeSample),
  73982. new CodeSample(
  73983. $codeSample,
  73984. ['strings_containing_single_quote_chars' => true]
  73985. ),
  73986. ]
  73987. );
  73988. }
  73989. public function getPriority(): int
  73990. {
  73991. return 10;
  73992. }
  73993. public function isCandidate(Tokens $tokens): bool
  73994. {
  73995. return $tokens->isTokenKindFound(T_CONSTANT_ENCAPSED_STRING);
  73996. }
  73997. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  73998. {
  73999. foreach ($tokens as $index => $token) {
  74000. if (!$token->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  74001. continue;
  74002. }
  74003. $content = $token->getContent();
  74004. $prefix = '';
  74005. if ('b' === strtolower($content[0])) {
  74006. $prefix = $content[0];
  74007. $content = substr($content, 1);
  74008. }
  74009. if (
  74010. '"' === $content[0]
  74011. && (true === $this->configuration['strings_containing_single_quote_chars'] || !str_contains($content, "'"))
  74012. && !Preg::match('/(?<!\\\)(?:\\\{2})*\\\(?!["$\\\])/', $content)
  74013. ) {
  74014. $content = substr($content, 1, -1);
  74015. $content = str_replace(['\"', '\$', '\''], ['"', '$', '\\\''], $content);
  74016. $tokens[$index] = new Token([T_CONSTANT_ENCAPSED_STRING, $prefix.'\''.$content.'\'']);
  74017. }
  74018. }
  74019. }
  74020. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74021. {
  74022. return new FixerConfigurationResolver([
  74023. (new FixerOptionBuilder('strings_containing_single_quote_chars', 'Whether to fix double-quoted strings that contains single-quotes.'))
  74024. ->setAllowedTypes(['bool'])
  74025. ->setDefault(false)
  74026. ->getOption(),
  74027. ]);
  74028. }
  74029. }
  74030. <?php
  74031. declare(strict_types=1);
  74032. namespace PhpCsFixer\Fixer\StringNotation;
  74033. use PhpCsFixer\AbstractFixer;
  74034. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74035. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74036. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74037. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74038. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74039. use PhpCsFixer\FixerDefinition\CodeSample;
  74040. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74041. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74042. use PhpCsFixer\Preg;
  74043. use PhpCsFixer\Tokenizer\Token;
  74044. use PhpCsFixer\Tokenizer\Tokens;
  74045. /**
  74046. @phpstan-type
  74047. @phpstan-type
  74048. @implements
  74049. */
  74050. final class StringImplicitBackslashesFixer extends AbstractFixer implements ConfigurableFixerInterface
  74051. {
  74052. /**
  74053. @use */
  74054. use ConfigurableFixerTrait;
  74055. public function getDefinition(): FixerDefinitionInterface
  74056. {
  74057. $codeSample = <<<'EOF'
  74058. <?php
  74059. $singleQuoted = 'String with \" and My\Prefix\\';
  74060. $doubleQuoted = "Interpret my \n but not my \a";
  74061. $hereDoc = <<<HEREDOC
  74062. Interpret my \100 but not my \999
  74063. HEREDOC;
  74064. EOF;
  74065. return new FixerDefinition(
  74066. 'Handles implicit backslashes in strings and heredocs. Depending on the chosen strategy, it can escape implicit backslashes to ease the understanding of which are special chars interpreted by PHP and which not (`escape`), or it can remove these additional backslashes if you find them superfluous (`unescape`). You can also leave them as-is using `ignore` strategy.',
  74067. [
  74068. new CodeSample($codeSample),
  74069. new CodeSample(
  74070. $codeSample,
  74071. ['single_quoted' => 'escape']
  74072. ),
  74073. new CodeSample(
  74074. $codeSample,
  74075. ['double_quoted' => 'unescape']
  74076. ),
  74077. new CodeSample(
  74078. $codeSample,
  74079. ['heredoc' => 'unescape']
  74080. ),
  74081. ],
  74082. 'In PHP double-quoted strings and heredocs some chars like `n`, `$` or `u` have special meanings if preceded by a backslash '
  74083. .'(and some are special only if followed by other special chars), while a backslash preceding other chars are interpreted like a plain '
  74084. .'backslash. The precise list of those special chars is hard to remember and to identify quickly: this fixer escapes backslashes '
  74085. ."that do not start a special interpretation with the char after them.\n"
  74086. .'It is possible to fix also single-quoted strings: in this case there is no special chars apart from single-quote and backslash '
  74087. .'itself, so the fixer simply ensure that all backslashes are escaped. Both single and double backslashes are allowed in single-quoted '
  74088. .'strings, so the purpose in this context is mainly to have a uniformed way to have them written all over the codebase.'
  74089. );
  74090. }
  74091. public function isCandidate(Tokens $tokens): bool
  74092. {
  74093. return $tokens->isAnyTokenKindsFound([T_ENCAPSED_AND_WHITESPACE, T_CONSTANT_ENCAPSED_STRING]);
  74094. }
  74095. public function getPriority(): int
  74096. {
  74097. return 15;
  74098. }
  74099. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74100. {
  74101. $singleQuotedReservedRegex = '[\'\\\]';
  74102. $doubleQuotedReservedRegex = '(?:[efnrtv$"\\\0-7]|x[0-9A-Fa-f]|u{|$)';
  74103. $heredocSyntaxReservedRegex = '(?:[efnrtv$\\\0-7]|x[0-9A-Fa-f]|u{|$)';
  74104. $doubleQuoteOpened = false;
  74105. foreach ($tokens as $index => $token) {
  74106. if ($token->equalsAny(['"', 'b"', 'B"'])) {
  74107. $doubleQuoteOpened = !$doubleQuoteOpened;
  74108. }
  74109. if (!$token->isGivenKind([T_ENCAPSED_AND_WHITESPACE, T_CONSTANT_ENCAPSED_STRING])) {
  74110. continue;
  74111. }
  74112. $content = $token->getContent();
  74113. if (!str_contains($content, '\\')) {
  74114. continue;
  74115. }
  74116. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE) && '\'' === substr(rtrim($tokens[$index - 1]->getContent()), -1)) {
  74117. continue;
  74118. }
  74119. $firstTwoCharacters = strtolower(substr($content, 0, 2));
  74120. $isSingleQuotedString = $token->isGivenKind(T_CONSTANT_ENCAPSED_STRING) && ('\'' === $content[0] || 'b\'' === $firstTwoCharacters);
  74121. $isDoubleQuotedString = ($token->isGivenKind(T_CONSTANT_ENCAPSED_STRING) && ('"' === $content[0] || 'b"' === $firstTwoCharacters))
  74122. || ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE) && $doubleQuoteOpened);
  74123. if ($isSingleQuotedString
  74124. ? 'ignore' === $this->configuration['single_quoted']
  74125. : ($isDoubleQuotedString
  74126. ? 'ignore' === $this->configuration['double_quoted']
  74127. : 'ignore' === $this->configuration['heredoc'])
  74128. ) {
  74129. continue;
  74130. }
  74131. $escapeBackslashes = $isSingleQuotedString
  74132. ? 'escape' === $this->configuration['single_quoted']
  74133. : ($isDoubleQuotedString
  74134. ? 'escape' === $this->configuration['double_quoted']
  74135. : 'escape' === $this->configuration['heredoc']);
  74136. $reservedRegex = $isSingleQuotedString
  74137. ? $singleQuotedReservedRegex
  74138. : ($isDoubleQuotedString
  74139. ? $doubleQuotedReservedRegex
  74140. : $heredocSyntaxReservedRegex);
  74141. if ($escapeBackslashes) {
  74142. $regex = '/(?<!\\\)\\\((?:\\\\\\\)*)(?!'.$reservedRegex.')/';
  74143. $newContent = Preg::replace($regex, '\\\\\\\$1', $content);
  74144. } else {
  74145. $regex = '/(?<!\\\)\\\\\\\((?:\\\\\\\)*)(?!'.$reservedRegex.')/';
  74146. $newContent = Preg::replace($regex, '\\\$1', $content);
  74147. }
  74148. if ($newContent !== $content) {
  74149. $tokens[$index] = new Token([$token->getId(), $newContent]);
  74150. }
  74151. }
  74152. }
  74153. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74154. {
  74155. return new FixerConfigurationResolver([
  74156. (new FixerOptionBuilder('single_quoted', 'Whether to escape backslashes in single-quoted strings.'))
  74157. ->setAllowedValues(['escape', 'unescape', 'ignore'])
  74158. ->setDefault('unescape')
  74159. ->getOption(),
  74160. (new FixerOptionBuilder('double_quoted', 'Whether to escape backslashes in double-quoted strings.'))
  74161. ->setAllowedValues(['escape', 'unescape', 'ignore'])
  74162. ->setDefault('escape')
  74163. ->getOption(),
  74164. (new FixerOptionBuilder('heredoc', 'Whether to escape backslashes in heredoc syntax.'))
  74165. ->setAllowedValues(['escape', 'unescape', 'ignore'])
  74166. ->setDefault('escape')
  74167. ->getOption(),
  74168. ]);
  74169. }
  74170. }
  74171. <?php
  74172. declare(strict_types=1);
  74173. namespace PhpCsFixer\Fixer\StringNotation;
  74174. use PhpCsFixer\AbstractFixer;
  74175. use PhpCsFixer\FixerDefinition\CodeSample;
  74176. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74177. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74178. use PhpCsFixer\Preg;
  74179. use PhpCsFixer\Tokenizer\Token;
  74180. use PhpCsFixer\Tokenizer\Tokens;
  74181. final class MultilineStringToHeredocFixer extends AbstractFixer
  74182. {
  74183. public function getDefinition(): FixerDefinitionInterface
  74184. {
  74185. return new FixerDefinition(
  74186. 'Convert multiline string to `heredoc` or `nowdoc`.',
  74187. [
  74188. new CodeSample(
  74189. <<<'EOD'
  74190. <?php
  74191. $a = 'line1
  74192. line2';
  74193. EOD."\n"
  74194. ),
  74195. new CodeSample(
  74196. <<<'EOD'
  74197. <?php
  74198. $a = "line1
  74199. {$obj->getName()}";
  74200. EOD."\n"
  74201. ),
  74202. ]
  74203. );
  74204. }
  74205. public function isCandidate(Tokens $tokens): bool
  74206. {
  74207. return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE]);
  74208. }
  74209. public function getPriority(): int
  74210. {
  74211. return 16;
  74212. }
  74213. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74214. {
  74215. $complexStringStartIndex = null;
  74216. foreach ($tokens as $index => $token) {
  74217. if (null === $complexStringStartIndex) {
  74218. if ($token->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  74219. $this->convertStringToHeredoc($tokens, $index, $index);
  74220. } elseif ($token->equalsAny(['"', 'b"', 'B"'])) {
  74221. $complexStringStartIndex = $index;
  74222. }
  74223. } elseif ($token->equals('"')) {
  74224. $this->convertStringToHeredoc($tokens, $complexStringStartIndex, $index);
  74225. $complexStringStartIndex = null;
  74226. }
  74227. }
  74228. }
  74229. private function convertStringToHeredoc(Tokens $tokens, int $stringStartIndex, int $stringEndIndex): void
  74230. {
  74231. $closingMarker = 'EOD';
  74232. if ($tokens[$stringStartIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  74233. $content = $tokens[$stringStartIndex]->getContent();
  74234. if ('b' === strtolower(substr($content, 0, 1))) {
  74235. $content = substr($content, 1);
  74236. }
  74237. $isSingleQuoted = str_starts_with($content, '\'');
  74238. $content = substr($content, 1, -1);
  74239. if ($isSingleQuoted) {
  74240. $content = Preg::replace('~\\\([\\\\\'])~', '$1', $content);
  74241. } else {
  74242. $content = Preg::replace('~(\\\\\\\)|\\\(")~', '$1$2', $content);
  74243. }
  74244. $constantStringToken = new Token([T_ENCAPSED_AND_WHITESPACE, $content."\n"]);
  74245. } else {
  74246. $content = $tokens->generatePartialCode($stringStartIndex + 1, $stringEndIndex - 1);
  74247. $isSingleQuoted = false;
  74248. $constantStringToken = null;
  74249. }
  74250. if (!str_contains($content, "\n") && !str_contains($content, "\r")) {
  74251. return;
  74252. }
  74253. while (Preg::match('~(^|[\r\n])\s*'.preg_quote($closingMarker, '~').'(?!\w)~', $content)) {
  74254. $closingMarker .= '_';
  74255. }
  74256. $quoting = $isSingleQuoted ? '\'' : '';
  74257. $heredocStartToken = new Token([T_START_HEREDOC, '<<<'.$quoting.$closingMarker.$quoting."\n"]);
  74258. $heredocEndToken = new Token([T_END_HEREDOC, $closingMarker]);
  74259. if (null !== $constantStringToken) {
  74260. $tokens->overrideRange($stringStartIndex, $stringEndIndex, [
  74261. $heredocStartToken,
  74262. $constantStringToken,
  74263. $heredocEndToken,
  74264. ]);
  74265. } else {
  74266. for ($i = $stringStartIndex + 1; $i < $stringEndIndex; ++$i) {
  74267. if ($tokens[$i]->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  74268. $tokens[$i] = new Token([
  74269. $tokens[$i]->getId(),
  74270. Preg::replace('~(\\\\\\\)|\\\(")~', '$1$2', $tokens[$i]->getContent()),
  74271. ]);
  74272. }
  74273. }
  74274. $tokens[$stringStartIndex] = $heredocStartToken;
  74275. $tokens[$stringEndIndex] = $heredocEndToken;
  74276. if ($tokens[$stringEndIndex - 1]->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  74277. $tokens[$stringEndIndex - 1] = new Token([
  74278. $tokens[$stringEndIndex - 1]->getId(),
  74279. $tokens[$stringEndIndex - 1]->getContent()."\n",
  74280. ]);
  74281. } else {
  74282. $tokens->insertAt($stringEndIndex, new Token([
  74283. T_ENCAPSED_AND_WHITESPACE,
  74284. "\n",
  74285. ]));
  74286. }
  74287. }
  74288. }
  74289. }
  74290. <?php
  74291. declare(strict_types=1);
  74292. namespace PhpCsFixer\Fixer\StringNotation;
  74293. use PhpCsFixer\AbstractProxyFixer;
  74294. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74295. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74296. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  74297. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74298. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74299. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74300. use PhpCsFixer\FixerDefinition\CodeSample;
  74301. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74302. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74303. /**
  74304. @phpstan-type
  74305. @phpstan-type
  74306. @implements
  74307. */
  74308. final class EscapeImplicitBackslashesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface
  74309. {
  74310. /**
  74311. @use */
  74312. use ConfigurableFixerTrait;
  74313. public function getSuccessorsNames(): array
  74314. {
  74315. return array_keys($this->proxyFixers);
  74316. }
  74317. public function getDefinition(): FixerDefinitionInterface
  74318. {
  74319. $codeSample = <<<'EOF'
  74320. <?php
  74321. $singleQuoted = 'String with \" and My\Prefix\\';
  74322. $doubleQuoted = "Interpret my \n but not my \a";
  74323. $hereDoc = <<<HEREDOC
  74324. Interpret my \100 but not my \999
  74325. HEREDOC;
  74326. EOF;
  74327. return new FixerDefinition(
  74328. 'Escape implicit backslashes in strings and heredocs to ease the understanding of which are special chars interpreted by PHP and which not.',
  74329. [
  74330. new CodeSample($codeSample),
  74331. new CodeSample(
  74332. $codeSample,
  74333. ['single_quoted' => true]
  74334. ),
  74335. new CodeSample(
  74336. $codeSample,
  74337. ['double_quoted' => false]
  74338. ),
  74339. new CodeSample(
  74340. $codeSample,
  74341. ['heredoc_syntax' => false]
  74342. ),
  74343. ],
  74344. 'In PHP double-quoted strings and heredocs some chars like `n`, `$` or `u` have special meanings if preceded by a backslash '
  74345. .'(and some are special only if followed by other special chars), while a backslash preceding other chars are interpreted like a plain '
  74346. .'backslash. The precise list of those special chars is hard to remember and to identify quickly: this fixer escapes backslashes '
  74347. ."that do not start a special interpretation with the char after them.\n"
  74348. .'It is possible to fix also single-quoted strings: in this case there is no special chars apart from single-quote and backslash '
  74349. .'itself, so the fixer simply ensure that all backslashes are escaped. Both single and double backslashes are allowed in single-quoted '
  74350. .'strings, so the purpose in this context is mainly to have a uniformed way to have them written all over the codebase.'
  74351. );
  74352. }
  74353. public function getPriority(): int
  74354. {
  74355. return parent::getPriority();
  74356. }
  74357. protected function configurePostNormalisation(): void
  74358. {
  74359. $stringImplicitBackslashesFixer = $this->proxyFixers['string_implicit_backslashes'];
  74360. $stringImplicitBackslashesFixer->configure([
  74361. 'single_quoted' => true === $this->configuration['single_quoted'] ? 'escape' : 'ignore',
  74362. 'double_quoted' => true === $this->configuration['double_quoted'] ? 'escape' : 'ignore',
  74363. 'heredoc' => true === $this->configuration['heredoc_syntax'] ? 'escape' : 'ignore',
  74364. ]);
  74365. }
  74366. protected function createProxyFixers(): array
  74367. {
  74368. $stringImplicitBackslashesFixer = new StringImplicitBackslashesFixer();
  74369. $stringImplicitBackslashesFixer->configure([
  74370. 'single_quoted' => 'ignore',
  74371. 'double_quoted' => 'escape',
  74372. 'heredoc' => 'escape',
  74373. ]);
  74374. return [
  74375. $stringImplicitBackslashesFixer,
  74376. ];
  74377. }
  74378. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74379. {
  74380. return new FixerConfigurationResolver([
  74381. (new FixerOptionBuilder('single_quoted', 'Whether to fix single-quoted strings.'))
  74382. ->setAllowedTypes(['bool'])
  74383. ->setDefault(false)
  74384. ->getOption(),
  74385. (new FixerOptionBuilder('double_quoted', 'Whether to fix double-quoted strings.'))
  74386. ->setAllowedTypes(['bool'])
  74387. ->setDefault(true)
  74388. ->getOption(),
  74389. (new FixerOptionBuilder('heredoc_syntax', 'Whether to fix heredoc syntax.'))
  74390. ->setAllowedTypes(['bool'])
  74391. ->setDefault(true)
  74392. ->getOption(),
  74393. ]);
  74394. }
  74395. }
  74396. <?php
  74397. declare(strict_types=1);
  74398. namespace PhpCsFixer\Fixer\StringNotation;
  74399. use PhpCsFixer\AbstractFixer;
  74400. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  74401. use PhpCsFixer\FixerDefinition\CodeSample;
  74402. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74403. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74404. use PhpCsFixer\Preg;
  74405. use PhpCsFixer\Tokenizer\Token;
  74406. use PhpCsFixer\Tokenizer\Tokens;
  74407. final class StringLineEndingFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  74408. {
  74409. public function isCandidate(Tokens $tokens): bool
  74410. {
  74411. return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML]);
  74412. }
  74413. public function isRisky(): bool
  74414. {
  74415. return true;
  74416. }
  74417. public function getDefinition(): FixerDefinitionInterface
  74418. {
  74419. return new FixerDefinition(
  74420. 'All multi-line strings must use correct line ending.',
  74421. [
  74422. new CodeSample(
  74423. "<?php \$a = 'my\r\nmulti\nline\r\nstring';\r\n"
  74424. ),
  74425. ],
  74426. null,
  74427. 'Changing the line endings of multi-line strings might affect string comparisons and outputs.'
  74428. );
  74429. }
  74430. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74431. {
  74432. $ending = $this->whitespacesConfig->getLineEnding();
  74433. foreach ($tokens as $tokenIndex => $token) {
  74434. if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_INLINE_HTML])) {
  74435. continue;
  74436. }
  74437. $tokens[$tokenIndex] = new Token([
  74438. $token->getId(),
  74439. Preg::replace(
  74440. '#\R#u',
  74441. $ending,
  74442. $token->getContent()
  74443. ),
  74444. ]);
  74445. }
  74446. }
  74447. }
  74448. <?php
  74449. declare(strict_types=1);
  74450. namespace PhpCsFixer\Fixer\AttributeNotation;
  74451. use PhpCsFixer\AbstractFixer;
  74452. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74453. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74454. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74455. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74456. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74457. use PhpCsFixer\FixerDefinition\CodeSample;
  74458. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74459. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74460. use PhpCsFixer\Tokenizer\Analyzer\Analysis\AttributeAnalysis;
  74461. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  74462. use PhpCsFixer\Tokenizer\FCT;
  74463. use PhpCsFixer\Tokenizer\Tokens;
  74464. /**
  74465. @phpstan-import-type
  74466. @phpstan-import-type
  74467. @phpstan-type
  74468. @phpstan-type
  74469. @implements
  74470. */
  74471. final class GeneralAttributeRemoveFixer extends AbstractFixer implements ConfigurableFixerInterface
  74472. {
  74473. /**
  74474. @use */
  74475. use ConfigurableFixerTrait;
  74476. public function getDefinition(): FixerDefinitionInterface
  74477. {
  74478. return new FixerDefinition(
  74479. 'Removes configured attributes by their respective FQN.',
  74480. [
  74481. new CodeSample(
  74482. '<?php
  74483. #[\A\B\Foo]
  74484. function foo() {}
  74485. ',
  74486. ['attributes' => ['\A\B\Foo']]
  74487. ),
  74488. new CodeSample(
  74489. '<?php
  74490. use A\B\Bar as BarAlias;
  74491. #[\A\B\Foo]
  74492. #[BarAlias]
  74493. function foo() {}
  74494. ',
  74495. ['attributes' => ['\A\B\Foo', 'A\B\Bar']]
  74496. ),
  74497. ]
  74498. );
  74499. }
  74500. public function getPriority(): int
  74501. {
  74502. return 0;
  74503. }
  74504. public function isCandidate(Tokens $tokens): bool
  74505. {
  74506. return $tokens->isTokenKindFound(FCT::T_ATTRIBUTE);
  74507. }
  74508. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74509. {
  74510. if (0 === \count($this->configuration['attributes'])) {
  74511. return;
  74512. }
  74513. $index = 0;
  74514. while (null !== $index = $tokens->getNextTokenOfKind($index, [[T_ATTRIBUTE]])) {
  74515. $attributeAnalysis = AttributeAnalyzer::collectOne($tokens, $index);
  74516. $endIndex = $attributeAnalysis->getEndIndex();
  74517. $removedCount = 0;
  74518. foreach ($attributeAnalysis->getAttributes() as $element) {
  74519. $fullname = AttributeAnalyzer::determineAttributeFullyQualifiedName($tokens, $element['name'], $element['start']);
  74520. if (!\in_array($fullname, $this->configuration['attributes'], true)) {
  74521. continue;
  74522. }
  74523. $tokens->clearRange($element['start'], $element['end']);
  74524. ++$removedCount;
  74525. $siblingIndex = $tokens->getNonEmptySibling($element['end'], 1);
  74526. if (',' === $tokens[$siblingIndex]->getContent()) {
  74527. $tokens->clearAt($siblingIndex);
  74528. }
  74529. }
  74530. if (\count($attributeAnalysis->getAttributes()) === $removedCount) {
  74531. $tokens->clearRange($attributeAnalysis->getStartIndex(), $attributeAnalysis->getEndIndex());
  74532. }
  74533. $tokenIndex = $tokens->getMeaningfulTokenSibling($attributeAnalysis->getClosingBracketIndex(), -1);
  74534. if (',' === $tokens[$tokenIndex]->getContent()) {
  74535. $tokens->clearAt($tokenIndex);
  74536. }
  74537. $index = $endIndex;
  74538. }
  74539. }
  74540. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74541. {
  74542. return new FixerConfigurationResolver([
  74543. (new FixerOptionBuilder('attributes', 'List of FQNs of attributes for removal.'))
  74544. ->setAllowedTypes(['class-string[]'])
  74545. ->setDefault([])
  74546. ->getOption(),
  74547. ]);
  74548. }
  74549. }
  74550. <?php
  74551. declare(strict_types=1);
  74552. namespace PhpCsFixer\Fixer\AttributeNotation;
  74553. use PhpCsFixer\AbstractFixer;
  74554. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74555. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74556. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74557. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74558. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74559. use PhpCsFixer\FixerDefinition\CodeSample;
  74560. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74561. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74562. use PhpCsFixer\Tokenizer\CT;
  74563. use PhpCsFixer\Tokenizer\FCT;
  74564. use PhpCsFixer\Tokenizer\Token;
  74565. use PhpCsFixer\Tokenizer\Tokens;
  74566. /**
  74567. @phpstan-type
  74568. @phpstan-type
  74569. @implements
  74570. */
  74571. final class AttributeEmptyParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
  74572. {
  74573. /**
  74574. @use */
  74575. use ConfigurableFixerTrait;
  74576. public function getDefinition(): FixerDefinitionInterface
  74577. {
  74578. return new FixerDefinition(
  74579. 'PHP attributes declared without arguments must (not) be followed by empty parentheses.',
  74580. [
  74581. new CodeSample("<?php\n\n#[Foo()]\nclass Sample1 {}\n\n#[Bar(), Baz()]\nclass Sample2 {}\n"),
  74582. new CodeSample(
  74583. "<?php\n\n#[Foo]\nclass Sample1 {}\n\n#[Bar, Baz]\nclass Sample2 {}\n",
  74584. ['use_parentheses' => true]
  74585. ),
  74586. ]
  74587. );
  74588. }
  74589. public function isCandidate(Tokens $tokens): bool
  74590. {
  74591. return $tokens->isTokenKindFound(FCT::T_ATTRIBUTE);
  74592. }
  74593. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74594. {
  74595. return new FixerConfigurationResolver([
  74596. (new FixerOptionBuilder('use_parentheses', 'Whether attributes should be followed by parentheses or not.'))
  74597. ->setAllowedTypes(['bool'])
  74598. ->setDefault(false)
  74599. ->getOption(),
  74600. ]);
  74601. }
  74602. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74603. {
  74604. $index = 0;
  74605. while (null !== $index = $tokens->getNextTokenOfKind($index, [[T_ATTRIBUTE]])) {
  74606. $nextIndex = $index;
  74607. do {
  74608. $parenthesesIndex = $tokens->getNextTokenOfKind($nextIndex, ['(', ',', [CT::T_ATTRIBUTE_CLOSE]]);
  74609. if (true === $this->configuration['use_parentheses']) {
  74610. $this->ensureParenthesesAt($tokens, $parenthesesIndex);
  74611. } else {
  74612. $this->ensureNoParenthesesAt($tokens, $parenthesesIndex);
  74613. }
  74614. $nextIndex = $tokens->getNextTokenOfKind($nextIndex, ['(', ',', [CT::T_ATTRIBUTE_CLOSE]]);
  74615. if ($tokens[$nextIndex]->equals('(')) {
  74616. $nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  74617. $nextIndex = $tokens->getNextTokenOfKind($nextIndex, [',', [CT::T_ATTRIBUTE_CLOSE]]);
  74618. }
  74619. if (!$tokens[$nextIndex]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  74620. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  74621. }
  74622. } while (!$tokens[$nextIndex]->isGivenKind(CT::T_ATTRIBUTE_CLOSE));
  74623. }
  74624. }
  74625. private function ensureParenthesesAt(Tokens $tokens, int $index): void
  74626. {
  74627. if ($tokens[$index]->equals('(')) {
  74628. return;
  74629. }
  74630. $tokens->insertAt(
  74631. $tokens->getPrevMeaningfulToken($index) + 1,
  74632. [new Token('('), new Token(')')]
  74633. );
  74634. }
  74635. private function ensureNoParenthesesAt(Tokens $tokens, int $index): void
  74636. {
  74637. if (!$tokens[$index]->equals('(')) {
  74638. return;
  74639. }
  74640. $closingIndex = $tokens->getNextMeaningfulToken($index);
  74641. if (!$tokens[$closingIndex]->equals(')')) {
  74642. return;
  74643. }
  74644. $tokens->clearTokenAndMergeSurroundingWhitespace($closingIndex);
  74645. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  74646. }
  74647. }
  74648. <?php
  74649. declare(strict_types=1);
  74650. namespace PhpCsFixer\Fixer\AttributeNotation;
  74651. use PhpCsFixer\AbstractFixer;
  74652. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  74653. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74654. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74655. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74656. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74657. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74658. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74659. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74660. use PhpCsFixer\FixerDefinition\VersionSpecification;
  74661. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  74662. use PhpCsFixer\Tokenizer\Analyzer\Analysis\AttributeAnalysis;
  74663. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  74664. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  74665. use PhpCsFixer\Tokenizer\Analyzer\FullyQualifiedNameAnalyzer;
  74666. use PhpCsFixer\Tokenizer\FCT;
  74667. use PhpCsFixer\Tokenizer\Token;
  74668. use PhpCsFixer\Tokenizer\Tokens;
  74669. use Symfony\Component\OptionsResolver\Options;
  74670. /**
  74671. @phpstan-import-type
  74672. @phpstan-type
  74673. @phpstan-type
  74674. @implements
  74675. */
  74676. final class OrderedAttributesFixer extends AbstractFixer implements ConfigurableFixerInterface
  74677. {
  74678. /**
  74679. @use */
  74680. use ConfigurableFixerTrait;
  74681. public const ORDER_ALPHA = 'alpha';
  74682. public const ORDER_CUSTOM = 'custom';
  74683. private const SUPPORTED_SORT_ALGORITHMS = [
  74684. self::ORDER_ALPHA,
  74685. self::ORDER_CUSTOM,
  74686. ];
  74687. public function getDefinition(): FixerDefinitionInterface
  74688. {
  74689. return new FixerDefinition(
  74690. 'Sorts attributes using the configured sort algorithm.',
  74691. [
  74692. new VersionSpecificCodeSample(
  74693. <<<'EOL'
  74694. <?php
  74695. #[Foo]
  74696. #[Bar(3)]
  74697. #[Qux(new Bar(5))]
  74698. #[Corge(a: 'test')]
  74699. class Sample1 {}
  74700. #[
  74701. Foo,
  74702. Bar(3),
  74703. Qux(new Bar(5)),
  74704. Corge(a: 'test'),
  74705. ]
  74706. class Sample2 {}
  74707. EOL,
  74708. new VersionSpecification(8_00_00),
  74709. ),
  74710. new VersionSpecificCodeSample(
  74711. <<<'EOL'
  74712. <?php
  74713. use A\B\Foo;
  74714. use A\B\Bar as BarAlias;
  74715. use A\B as AB;
  74716. #[Foo]
  74717. #[BarAlias(3)]
  74718. #[AB\Qux(new Bar(5))]
  74719. #[\A\B\Corge(a: 'test')]
  74720. class Sample1 {}
  74721. EOL,
  74722. new VersionSpecification(8_00_00),
  74723. ['sort_algorithm' => self::ORDER_CUSTOM, 'order' => ['A\B\Qux', 'A\B\Bar', 'A\B\Corge']],
  74724. ),
  74725. ],
  74726. );
  74727. }
  74728. public function getPriority(): int
  74729. {
  74730. return 0;
  74731. }
  74732. public function isCandidate(Tokens $tokens): bool
  74733. {
  74734. return $tokens->isTokenKindFound(FCT::T_ATTRIBUTE);
  74735. }
  74736. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74737. {
  74738. $fixerName = $this->getName();
  74739. return new FixerConfigurationResolver([
  74740. (new FixerOptionBuilder('sort_algorithm', 'How the attributes should be sorted.'))
  74741. ->setAllowedValues(self::SUPPORTED_SORT_ALGORITHMS)
  74742. ->setDefault(self::ORDER_ALPHA)
  74743. ->setNormalizer(static function (Options $options, string $value) use ($fixerName): string {
  74744. if (self::ORDER_CUSTOM === $value && [] === $options['order']) {
  74745. throw new InvalidFixerConfigurationException(
  74746. $fixerName,
  74747. 'The custom order strategy requires providing `order` option with a list of attributes\'s FQNs.'
  74748. );
  74749. }
  74750. return $value;
  74751. })
  74752. ->getOption(),
  74753. (new FixerOptionBuilder('order', 'A list of FQCNs of attributes defining the desired order used when custom sorting algorithm is configured.'))
  74754. ->setAllowedTypes(['string[]'])
  74755. ->setDefault([])
  74756. ->setNormalizer(static function (Options $options, array $value) use ($fixerName): array {
  74757. if ($value !== array_unique($value)) {
  74758. throw new InvalidFixerConfigurationException($fixerName, 'The list includes attributes that are not unique.');
  74759. }
  74760. return array_flip(array_values(
  74761. array_map(static fn (string $attribute): string => ltrim($attribute, '\\'), $value),
  74762. ));
  74763. })
  74764. ->getOption(),
  74765. ]);
  74766. }
  74767. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  74768. {
  74769. $fullyQualifiedNameAnalyzer = new FullyQualifiedNameAnalyzer($tokens);
  74770. $index = 0;
  74771. while (null !== $index = $tokens->getNextTokenOfKind($index, [[T_ATTRIBUTE]])) {
  74772. $elements = array_map(fn (AttributeAnalysis $attributeAnalysis): array => [
  74773. 'name' => $this->sortAttributes($fullyQualifiedNameAnalyzer, $tokens, $attributeAnalysis->getStartIndex(), $attributeAnalysis->getAttributes()),
  74774. 'start' => $attributeAnalysis->getStartIndex(),
  74775. 'end' => $attributeAnalysis->getEndIndex(),
  74776. ], AttributeAnalyzer::collect($tokens, $index));
  74777. $endIndex = end($elements)['end'];
  74778. try {
  74779. if (1 === \count($elements)) {
  74780. continue;
  74781. }
  74782. $sortedElements = $this->sortElements($elements);
  74783. if ($elements === $sortedElements) {
  74784. continue;
  74785. }
  74786. $this->sortTokens($tokens, $index, $endIndex, $sortedElements);
  74787. } finally {
  74788. $index = $endIndex;
  74789. }
  74790. }
  74791. }
  74792. private function sortAttributes(FullyQualifiedNameAnalyzer $fullyQualifiedNameAnalyzer, Tokens $tokens, int $index, array $attributes): string
  74793. {
  74794. if (1 === \count($attributes)) {
  74795. return $this->getAttributeName($fullyQualifiedNameAnalyzer, $attributes[0]['name'], $attributes[0]['start']);
  74796. }
  74797. foreach ($attributes as &$attribute) {
  74798. $attribute['name'] = $this->getAttributeName($fullyQualifiedNameAnalyzer, $attribute['name'], $attribute['start']);
  74799. }
  74800. $sortedElements = $this->sortElements($attributes);
  74801. if ($attributes === $sortedElements) {
  74802. return $attributes[0]['name'];
  74803. }
  74804. $this->sortTokens($tokens, $index + 1, end($attributes)['end'], $sortedElements, new Token(','));
  74805. return $sortedElements[0]['name'];
  74806. }
  74807. private function getAttributeName(FullyQualifiedNameAnalyzer $fullyQualifiedNameAnalyzer, string $name, int $index): string
  74808. {
  74809. if (self::ORDER_CUSTOM === $this->configuration['sort_algorithm']) {
  74810. return $fullyQualifiedNameAnalyzer->getFullyQualifiedName($name, $index, NamespaceUseAnalysis::TYPE_CLASS);
  74811. }
  74812. return ltrim($name, '\\');
  74813. }
  74814. private function sortElements(array $elements): array
  74815. {
  74816. usort($elements, function (array $a, array $b): int {
  74817. $sortAlgorithm = $this->configuration['sort_algorithm'];
  74818. if (self::ORDER_ALPHA === $sortAlgorithm) {
  74819. return $a['name'] <=> $b['name'];
  74820. }
  74821. if (self::ORDER_CUSTOM === $sortAlgorithm) {
  74822. return
  74823. ($this->configuration['order'][$a['name']] ?? PHP_INT_MAX)
  74824. <=> ($this->configuration['order'][$b['name']] ?? PHP_INT_MAX);
  74825. }
  74826. throw new \InvalidArgumentException(\sprintf('Invalid sort algorithm "%s" provided.', $sortAlgorithm));
  74827. });
  74828. return $elements;
  74829. }
  74830. private function sortTokens(Tokens $tokens, int $startIndex, int $endIndex, array $elements, ?Token $delimiter = null): void
  74831. {
  74832. $replaceTokens = [];
  74833. foreach ($elements as $pos => $element) {
  74834. for ($i = $element['start']; $i <= $element['end']; ++$i) {
  74835. $replaceTokens[] = clone $tokens[$i];
  74836. }
  74837. if (null !== $delimiter && $pos !== \count($elements) - 1) {
  74838. $replaceTokens[] = clone $delimiter;
  74839. }
  74840. }
  74841. $tokens->overrideRange($startIndex, $endIndex, $replaceTokens);
  74842. }
  74843. }
  74844. <?php
  74845. declare(strict_types=1);
  74846. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  74847. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  74848. use PhpCsFixer\Doctrine\Annotation\DocLexer;
  74849. use PhpCsFixer\Doctrine\Annotation\Tokens;
  74850. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74851. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74852. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74853. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74854. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  74855. use PhpCsFixer\FixerDefinition\CodeSample;
  74856. use PhpCsFixer\FixerDefinition\FixerDefinition;
  74857. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  74858. use PhpCsFixer\Preg;
  74859. /**
  74860. @phpstan-type
  74861. @phpstan-type
  74862. @implements
  74863. */
  74864. final class DoctrineAnnotationIndentationFixer extends AbstractDoctrineAnnotationFixer implements ConfigurableFixerInterface
  74865. {
  74866. /**
  74867. @use */
  74868. use ConfigurableFixerTrait;
  74869. public function getDefinition(): FixerDefinitionInterface
  74870. {
  74871. return new FixerDefinition(
  74872. 'Doctrine annotations must be indented with four spaces.',
  74873. [
  74874. new CodeSample("<?php\n/**\n * @Foo(\n * foo=\"foo\"\n * )\n */\nclass Bar {}\n"),
  74875. new CodeSample(
  74876. "<?php\n/**\n * @Foo({@Bar,\n * @Baz})\n */\nclass Bar {}\n",
  74877. ['indent_mixed_lines' => true]
  74878. ),
  74879. ]
  74880. );
  74881. }
  74882. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  74883. {
  74884. return new FixerConfigurationResolver([
  74885. ...parent::createConfigurationDefinition()->getOptions(),
  74886. (new FixerOptionBuilder('indent_mixed_lines', 'Whether to indent lines that have content before closing parenthesis.'))
  74887. ->setAllowedTypes(['bool'])
  74888. ->setDefault(false)
  74889. ->getOption(),
  74890. ]);
  74891. }
  74892. protected function fixAnnotations(Tokens $doctrineAnnotationTokens): void
  74893. {
  74894. $annotationPositions = [];
  74895. for ($index = 0, $max = \count($doctrineAnnotationTokens); $index < $max; ++$index) {
  74896. if (!$doctrineAnnotationTokens[$index]->isType(DocLexer::T_AT)) {
  74897. continue;
  74898. }
  74899. $annotationEndIndex = $doctrineAnnotationTokens->getAnnotationEnd($index);
  74900. if (null === $annotationEndIndex) {
  74901. return;
  74902. }
  74903. $annotationPositions[] = [$index, $annotationEndIndex];
  74904. $index = $annotationEndIndex;
  74905. }
  74906. $indentLevel = 0;
  74907. foreach ($doctrineAnnotationTokens as $index => $token) {
  74908. if (!$token->isType(DocLexer::T_NONE) || !str_contains($token->getContent(), "\n")) {
  74909. continue;
  74910. }
  74911. if (!$this->indentationCanBeFixed($doctrineAnnotationTokens, $index, $annotationPositions)) {
  74912. continue;
  74913. }
  74914. $braces = $this->getLineBracesCount($doctrineAnnotationTokens, $index);
  74915. $delta = $braces[0] - $braces[1];
  74916. $mixedBraces = 0 === $delta && $braces[0] > 0;
  74917. $extraIndentLevel = 0;
  74918. if ($indentLevel > 0 && ($delta < 0 || $mixedBraces)) {
  74919. --$indentLevel;
  74920. if (true === $this->configuration['indent_mixed_lines'] && $this->isClosingLineWithMeaningfulContent($doctrineAnnotationTokens, $index)) {
  74921. $extraIndentLevel = 1;
  74922. }
  74923. }
  74924. $token->setContent(Preg::replace(
  74925. '/(\n( +\*)?) *$/',
  74926. '$1'.str_repeat(' ', 4 * ($indentLevel + $extraIndentLevel) + 1),
  74927. $token->getContent()
  74928. ));
  74929. if ($delta > 0 || $mixedBraces) {
  74930. ++$indentLevel;
  74931. }
  74932. }
  74933. }
  74934. private function getLineBracesCount(Tokens $tokens, int $index): array
  74935. {
  74936. $opening = 0;
  74937. $closing = 0;
  74938. while (isset($tokens[++$index])) {
  74939. $token = $tokens[$index];
  74940. if ($token->isType(DocLexer::T_NONE) && str_contains($token->getContent(), "\n")) {
  74941. break;
  74942. }
  74943. if ($token->isType([DocLexer::T_OPEN_PARENTHESIS, DocLexer::T_OPEN_CURLY_BRACES])) {
  74944. ++$opening;
  74945. continue;
  74946. }
  74947. if (!$token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES])) {
  74948. continue;
  74949. }
  74950. if ($opening > 0) {
  74951. --$opening;
  74952. } else {
  74953. ++$closing;
  74954. }
  74955. }
  74956. return [$opening, $closing];
  74957. }
  74958. private function isClosingLineWithMeaningfulContent(Tokens $tokens, int $index): bool
  74959. {
  74960. while (isset($tokens[++$index])) {
  74961. $token = $tokens[$index];
  74962. if ($token->isType(DocLexer::T_NONE)) {
  74963. if (str_contains($token->getContent(), "\n")) {
  74964. return false;
  74965. }
  74966. continue;
  74967. }
  74968. return !$token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES]);
  74969. }
  74970. return false;
  74971. }
  74972. private function indentationCanBeFixed(Tokens $tokens, int $newLineTokenIndex, array $annotationPositions): bool
  74973. {
  74974. foreach ($annotationPositions as $position) {
  74975. if ($newLineTokenIndex >= $position[0] && $newLineTokenIndex <= $position[1]) {
  74976. return true;
  74977. }
  74978. }
  74979. for ($index = $newLineTokenIndex + 1, $max = \count($tokens); $index < $max; ++$index) {
  74980. $token = $tokens[$index];
  74981. if (str_contains($token->getContent(), "\n")) {
  74982. return false;
  74983. }
  74984. return $tokens[$index]->isType(DocLexer::T_AT);
  74985. }
  74986. return false;
  74987. }
  74988. }
  74989. <?php
  74990. declare(strict_types=1);
  74991. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  74992. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  74993. use PhpCsFixer\Doctrine\Annotation\DocLexer;
  74994. use PhpCsFixer\Doctrine\Annotation\Tokens;
  74995. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  74996. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  74997. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  74998. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  74999. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75000. use PhpCsFixer\FixerDefinition\CodeSample;
  75001. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75002. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  75003. /**
  75004. @phpstan-type
  75005. @phpstan-type
  75006. @implements
  75007. */
  75008. final class DoctrineAnnotationArrayAssignmentFixer extends AbstractDoctrineAnnotationFixer implements ConfigurableFixerInterface
  75009. {
  75010. /**
  75011. @use */
  75012. use ConfigurableFixerTrait;
  75013. public function getDefinition(): FixerDefinitionInterface
  75014. {
  75015. return new FixerDefinition(
  75016. 'Doctrine annotations must use configured operator for assignment in arrays.',
  75017. [
  75018. new CodeSample(
  75019. "<?php\n/**\n * @Foo({bar : \"baz\"})\n */\nclass Bar {}\n"
  75020. ),
  75021. new CodeSample(
  75022. "<?php\n/**\n * @Foo({bar = \"baz\"})\n */\nclass Bar {}\n",
  75023. ['operator' => ':']
  75024. ),
  75025. ]
  75026. );
  75027. }
  75028. public function getPriority(): int
  75029. {
  75030. return 1;
  75031. }
  75032. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  75033. {
  75034. $options = parent::createConfigurationDefinition()->getOptions();
  75035. $options[] = (new FixerOptionBuilder('operator', 'The operator to use.'))
  75036. ->setAllowedValues(['=', ':'])
  75037. ->setDefault('=')
  75038. ->getOption()
  75039. ;
  75040. return new FixerConfigurationResolver($options);
  75041. }
  75042. protected function fixAnnotations(Tokens $doctrineAnnotationTokens): void
  75043. {
  75044. $scopes = [];
  75045. foreach ($doctrineAnnotationTokens as $token) {
  75046. if ($token->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  75047. $scopes[] = 'annotation';
  75048. continue;
  75049. }
  75050. if ($token->isType(DocLexer::T_OPEN_CURLY_BRACES)) {
  75051. $scopes[] = 'array';
  75052. continue;
  75053. }
  75054. if ($token->isType([DocLexer::T_CLOSE_PARENTHESIS, DocLexer::T_CLOSE_CURLY_BRACES])) {
  75055. array_pop($scopes);
  75056. continue;
  75057. }
  75058. if ('array' === end($scopes) && $token->isType([DocLexer::T_EQUALS, DocLexer::T_COLON])) {
  75059. $token->setContent($this->configuration['operator']);
  75060. }
  75061. }
  75062. }
  75063. }
  75064. <?php
  75065. declare(strict_types=1);
  75066. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  75067. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  75068. use PhpCsFixer\Doctrine\Annotation\DocLexer;
  75069. use PhpCsFixer\Doctrine\Annotation\Token;
  75070. use PhpCsFixer\Doctrine\Annotation\Tokens;
  75071. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  75072. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  75073. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  75074. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  75075. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75076. use PhpCsFixer\FixerDefinition\CodeSample;
  75077. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75078. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  75079. use PhpCsFixer\Preg;
  75080. /**
  75081. @phpstan-type
  75082. @phpstan-type
  75083. @implements
  75084. */
  75085. final class DoctrineAnnotationSpacesFixer extends AbstractDoctrineAnnotationFixer implements ConfigurableFixerInterface
  75086. {
  75087. /**
  75088. @use */
  75089. use ConfigurableFixerTrait;
  75090. public function getDefinition(): FixerDefinitionInterface
  75091. {
  75092. return new FixerDefinition(
  75093. 'Fixes spaces in Doctrine annotations.',
  75094. [
  75095. new CodeSample(
  75096. "<?php\n/**\n * @Foo ( )\n */\nclass Bar {}\n\n/**\n * @Foo(\"bar\" ,\"baz\")\n */\nclass Bar2 {}\n\n/**\n * @Foo(foo = \"foo\", bar = {\"foo\":\"foo\", \"bar\"=\"bar\"})\n */\nclass Bar3 {}\n"
  75097. ),
  75098. new CodeSample(
  75099. "<?php\n/**\n * @Foo(foo = \"foo\", bar = {\"foo\":\"foo\", \"bar\"=\"bar\"})\n */\nclass Bar {}\n",
  75100. ['after_array_assignments_equals' => false, 'before_array_assignments_equals' => false]
  75101. ),
  75102. ],
  75103. 'There must not be any space around parentheses; commas must be preceded by no space and followed by one space; there must be no space around named arguments assignment operator; there must be one space around array assignment operator.'
  75104. );
  75105. }
  75106. public function getPriority(): int
  75107. {
  75108. return 0;
  75109. }
  75110. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  75111. {
  75112. return new FixerConfigurationResolver([
  75113. ...parent::createConfigurationDefinition()->getOptions(),
  75114. (new FixerOptionBuilder('around_parentheses', 'Whether to fix spaces around parentheses.'))
  75115. ->setAllowedTypes(['bool'])
  75116. ->setDefault(true)
  75117. ->getOption(),
  75118. (new FixerOptionBuilder('around_commas', 'Whether to fix spaces around commas.'))
  75119. ->setAllowedTypes(['bool'])
  75120. ->setDefault(true)
  75121. ->getOption(),
  75122. (new FixerOptionBuilder('before_argument_assignments', 'Whether to add, remove or ignore spaces before argument assignment operator.'))
  75123. ->setAllowedTypes(['null', 'bool'])
  75124. ->setDefault(false)
  75125. ->getOption(),
  75126. (new FixerOptionBuilder('after_argument_assignments', 'Whether to add, remove or ignore spaces after argument assignment operator.'))
  75127. ->setAllowedTypes(['null', 'bool'])
  75128. ->setDefault(false)
  75129. ->getOption(),
  75130. (new FixerOptionBuilder('before_array_assignments_equals', 'Whether to add, remove or ignore spaces before array `=` assignment operator.'))
  75131. ->setAllowedTypes(['null', 'bool'])
  75132. ->setDefault(true)
  75133. ->getOption(),
  75134. (new FixerOptionBuilder('after_array_assignments_equals', 'Whether to add, remove or ignore spaces after array assignment `=` operator.'))
  75135. ->setAllowedTypes(['null', 'bool'])
  75136. ->setDefault(true)
  75137. ->getOption(),
  75138. (new FixerOptionBuilder('before_array_assignments_colon', 'Whether to add, remove or ignore spaces before array `:` assignment operator.'))
  75139. ->setAllowedTypes(['null', 'bool'])
  75140. ->setDefault(true)
  75141. ->getOption(),
  75142. (new FixerOptionBuilder('after_array_assignments_colon', 'Whether to add, remove or ignore spaces after array assignment `:` operator.'))
  75143. ->setAllowedTypes(['null', 'bool'])
  75144. ->setDefault(true)
  75145. ->getOption(),
  75146. ]);
  75147. }
  75148. protected function fixAnnotations(Tokens $doctrineAnnotationTokens): void
  75149. {
  75150. if (true === $this->configuration['around_parentheses']) {
  75151. $this->fixSpacesAroundParentheses($doctrineAnnotationTokens);
  75152. }
  75153. if (true === $this->configuration['around_commas']) {
  75154. $this->fixSpacesAroundCommas($doctrineAnnotationTokens);
  75155. }
  75156. if (
  75157. null !== $this->configuration['before_argument_assignments']
  75158. || null !== $this->configuration['after_argument_assignments']
  75159. || null !== $this->configuration['before_array_assignments_equals']
  75160. || null !== $this->configuration['after_array_assignments_equals']
  75161. || null !== $this->configuration['before_array_assignments_colon']
  75162. || null !== $this->configuration['after_array_assignments_colon']
  75163. ) {
  75164. $this->fixAroundAssignments($doctrineAnnotationTokens);
  75165. }
  75166. }
  75167. private function fixSpacesAroundParentheses(Tokens $tokens): void
  75168. {
  75169. $inAnnotationUntilIndex = null;
  75170. foreach ($tokens as $index => $token) {
  75171. if (null !== $inAnnotationUntilIndex) {
  75172. if ($index === $inAnnotationUntilIndex) {
  75173. $inAnnotationUntilIndex = null;
  75174. continue;
  75175. }
  75176. } elseif ($token->isType(DocLexer::T_AT)) {
  75177. $endIndex = $tokens->getAnnotationEnd($index);
  75178. if (null !== $endIndex) {
  75179. $inAnnotationUntilIndex = $endIndex + 1;
  75180. }
  75181. continue;
  75182. }
  75183. if (null === $inAnnotationUntilIndex) {
  75184. continue;
  75185. }
  75186. if (!$token->isType([DocLexer::T_OPEN_PARENTHESIS, DocLexer::T_CLOSE_PARENTHESIS])) {
  75187. continue;
  75188. }
  75189. if ($token->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  75190. $token = $tokens[$index - 1];
  75191. if ($token->isType(DocLexer::T_NONE)) {
  75192. $token->clear();
  75193. }
  75194. $token = $tokens[$index + 1];
  75195. } else {
  75196. $token = $tokens[$index - 1];
  75197. }
  75198. if ($token->isType(DocLexer::T_NONE)) {
  75199. if (str_contains($token->getContent(), "\n")) {
  75200. continue;
  75201. }
  75202. $token->clear();
  75203. }
  75204. }
  75205. }
  75206. private function fixSpacesAroundCommas(Tokens $tokens): void
  75207. {
  75208. $inAnnotationUntilIndex = null;
  75209. foreach ($tokens as $index => $token) {
  75210. if (null !== $inAnnotationUntilIndex) {
  75211. if ($index === $inAnnotationUntilIndex) {
  75212. $inAnnotationUntilIndex = null;
  75213. continue;
  75214. }
  75215. } elseif ($token->isType(DocLexer::T_AT)) {
  75216. $endIndex = $tokens->getAnnotationEnd($index);
  75217. if (null !== $endIndex) {
  75218. $inAnnotationUntilIndex = $endIndex;
  75219. }
  75220. continue;
  75221. }
  75222. if (null === $inAnnotationUntilIndex) {
  75223. continue;
  75224. }
  75225. if (!$token->isType(DocLexer::T_COMMA)) {
  75226. continue;
  75227. }
  75228. $token = $tokens[$index - 1];
  75229. if ($token->isType(DocLexer::T_NONE)) {
  75230. $token->clear();
  75231. }
  75232. if ($index < \count($tokens) - 1 && !Preg::match('/^\s/', $tokens[$index + 1]->getContent())) {
  75233. $tokens->insertAt($index + 1, new Token(DocLexer::T_NONE, ' '));
  75234. }
  75235. }
  75236. }
  75237. private function fixAroundAssignments(Tokens $tokens): void
  75238. {
  75239. $beforeArguments = $this->configuration['before_argument_assignments'];
  75240. $afterArguments = $this->configuration['after_argument_assignments'];
  75241. $beforeArraysEquals = $this->configuration['before_array_assignments_equals'];
  75242. $afterArraysEquals = $this->configuration['after_array_assignments_equals'];
  75243. $beforeArraysColon = $this->configuration['before_array_assignments_colon'];
  75244. $afterArraysColon = $this->configuration['after_array_assignments_colon'];
  75245. $scopes = [];
  75246. foreach ($tokens as $index => $token) {
  75247. $endScopeType = end($scopes);
  75248. if (false !== $endScopeType && $token->isType($endScopeType)) {
  75249. array_pop($scopes);
  75250. continue;
  75251. }
  75252. if ($token->isType(DocLexer::T_AT)) {
  75253. $scopes[] = DocLexer::T_CLOSE_PARENTHESIS;
  75254. continue;
  75255. }
  75256. if ($token->isType(DocLexer::T_OPEN_CURLY_BRACES)) {
  75257. $scopes[] = DocLexer::T_CLOSE_CURLY_BRACES;
  75258. continue;
  75259. }
  75260. if (DocLexer::T_CLOSE_PARENTHESIS === $endScopeType && $token->isType(DocLexer::T_EQUALS)) {
  75261. $this->updateSpacesAfter($tokens, $index, $afterArguments);
  75262. $this->updateSpacesBefore($tokens, $index, $beforeArguments);
  75263. continue;
  75264. }
  75265. if (DocLexer::T_CLOSE_CURLY_BRACES === $endScopeType) {
  75266. if ($token->isType(DocLexer::T_EQUALS)) {
  75267. $this->updateSpacesAfter($tokens, $index, $afterArraysEquals);
  75268. $this->updateSpacesBefore($tokens, $index, $beforeArraysEquals);
  75269. continue;
  75270. }
  75271. if ($token->isType(DocLexer::T_COLON)) {
  75272. $this->updateSpacesAfter($tokens, $index, $afterArraysColon);
  75273. $this->updateSpacesBefore($tokens, $index, $beforeArraysColon);
  75274. }
  75275. }
  75276. }
  75277. }
  75278. private function updateSpacesAfter(Tokens $tokens, int $index, ?bool $insert): void
  75279. {
  75280. $this->updateSpacesAt($tokens, $index + 1, $index + 1, $insert);
  75281. }
  75282. private function updateSpacesBefore(Tokens $tokens, int $index, ?bool $insert): void
  75283. {
  75284. $this->updateSpacesAt($tokens, $index - 1, $index, $insert);
  75285. }
  75286. private function updateSpacesAt(Tokens $tokens, int $index, int $insertIndex, ?bool $insert): void
  75287. {
  75288. if (null === $insert) {
  75289. return;
  75290. }
  75291. $token = $tokens[$index];
  75292. if ($insert) {
  75293. if (!$token->isType(DocLexer::T_NONE)) {
  75294. $tokens->insertAt($insertIndex, $token = new Token());
  75295. }
  75296. $token->setContent(' ');
  75297. } elseif ($token->isType(DocLexer::T_NONE)) {
  75298. $token->clear();
  75299. }
  75300. }
  75301. }
  75302. <?php
  75303. declare(strict_types=1);
  75304. namespace PhpCsFixer\Fixer\DoctrineAnnotation;
  75305. use PhpCsFixer\AbstractDoctrineAnnotationFixer;
  75306. use PhpCsFixer\Doctrine\Annotation\DocLexer;
  75307. use PhpCsFixer\Doctrine\Annotation\Token;
  75308. use PhpCsFixer\Doctrine\Annotation\Tokens;
  75309. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  75310. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  75311. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  75312. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  75313. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75314. use PhpCsFixer\FixerDefinition\CodeSample;
  75315. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75316. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  75317. /**
  75318. @phpstan-type
  75319. @phpstan-type
  75320. @implements
  75321. */
  75322. final class DoctrineAnnotationBracesFixer extends AbstractDoctrineAnnotationFixer implements ConfigurableFixerInterface
  75323. {
  75324. /**
  75325. @use */
  75326. use ConfigurableFixerTrait;
  75327. public function getDefinition(): FixerDefinitionInterface
  75328. {
  75329. return new FixerDefinition(
  75330. 'Doctrine annotations without arguments must use the configured syntax.',
  75331. [
  75332. new CodeSample(
  75333. "<?php\n/**\n * @Foo()\n */\nclass Bar {}\n"
  75334. ),
  75335. new CodeSample(
  75336. "<?php\n/**\n * @Foo\n */\nclass Bar {}\n",
  75337. ['syntax' => 'with_braces']
  75338. ),
  75339. ]
  75340. );
  75341. }
  75342. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  75343. {
  75344. return new FixerConfigurationResolver([
  75345. ...parent::createConfigurationDefinition()->getOptions(),
  75346. (new FixerOptionBuilder('syntax', 'Whether to add or remove braces.'))
  75347. ->setAllowedValues(['with_braces', 'without_braces'])
  75348. ->setDefault('without_braces')
  75349. ->getOption(),
  75350. ]);
  75351. }
  75352. protected function fixAnnotations(Tokens $doctrineAnnotationTokens): void
  75353. {
  75354. if ('without_braces' === $this->configuration['syntax']) {
  75355. $this->removesBracesFromAnnotations($doctrineAnnotationTokens);
  75356. } else {
  75357. $this->addBracesToAnnotations($doctrineAnnotationTokens);
  75358. }
  75359. }
  75360. private function addBracesToAnnotations(Tokens $tokens): void
  75361. {
  75362. foreach ($tokens as $index => $token) {
  75363. if (!$token->isType(DocLexer::T_AT)) {
  75364. continue;
  75365. }
  75366. $braceIndex = $tokens->getNextMeaningfulToken($index + 1);
  75367. if (null !== $braceIndex && $tokens[$braceIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  75368. continue;
  75369. }
  75370. $tokens->insertAt($index + 2, new Token(DocLexer::T_OPEN_PARENTHESIS, '('));
  75371. $tokens->insertAt($index + 3, new Token(DocLexer::T_CLOSE_PARENTHESIS, ')'));
  75372. }
  75373. }
  75374. private function removesBracesFromAnnotations(Tokens $tokens): void
  75375. {
  75376. for ($index = 0, $max = \count($tokens); $index < $max; ++$index) {
  75377. if (!$tokens[$index]->isType(DocLexer::T_AT)) {
  75378. continue;
  75379. }
  75380. $openBraceIndex = $tokens->getNextMeaningfulToken($index + 1);
  75381. if (null === $openBraceIndex) {
  75382. continue;
  75383. }
  75384. if (!$tokens[$openBraceIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  75385. continue;
  75386. }
  75387. $closeBraceIndex = $tokens->getNextMeaningfulToken($openBraceIndex);
  75388. if (null === $closeBraceIndex) {
  75389. continue;
  75390. }
  75391. if (!$tokens[$closeBraceIndex]->isType(DocLexer::T_CLOSE_PARENTHESIS)) {
  75392. continue;
  75393. }
  75394. for ($currentIndex = $index + 2; $currentIndex <= $closeBraceIndex; ++$currentIndex) {
  75395. $tokens[$currentIndex]->clear();
  75396. }
  75397. }
  75398. }
  75399. }
  75400. <?php
  75401. declare(strict_types=1);
  75402. namespace PhpCsFixer\Fixer\PhpUnit;
  75403. use Composer\Semver\Comparator;
  75404. final class PhpUnitTargetVersion
  75405. {
  75406. public const VERSION_3_0 = '3.0';
  75407. public const VERSION_3_2 = '3.2';
  75408. public const VERSION_3_5 = '3.5';
  75409. public const VERSION_4_3 = '4.3';
  75410. public const VERSION_4_8 = '4.8';
  75411. public const VERSION_5_0 = '5.0';
  75412. public const VERSION_5_2 = '5.2';
  75413. public const VERSION_5_4 = '5.4';
  75414. public const VERSION_5_5 = '5.5';
  75415. public const VERSION_5_6 = '5.6';
  75416. public const VERSION_5_7 = '5.7';
  75417. public const VERSION_6_0 = '6.0';
  75418. public const VERSION_7_5 = '7.5';
  75419. public const VERSION_8_4 = '8.4';
  75420. public const VERSION_9_1 = '9.1';
  75421. public const VERSION_NEWEST = 'newest';
  75422. private function __construct() {}
  75423. public static function fulfills(string $candidate, string $target): bool
  75424. {
  75425. if (self::VERSION_NEWEST === $target) {
  75426. throw new \LogicException(\sprintf('Parameter `target` shall not be provided as "%s", determine proper target for tested PHPUnit feature instead.', self::VERSION_NEWEST));
  75427. }
  75428. if (self::VERSION_NEWEST === $candidate) {
  75429. return true;
  75430. }
  75431. return Comparator::greaterThanOrEqualTo($candidate, $target);
  75432. }
  75433. }
  75434. <?php
  75435. declare(strict_types=1);
  75436. namespace PhpCsFixer\Fixer\PhpUnit;
  75437. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  75438. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  75439. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  75440. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  75441. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  75442. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  75443. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75444. use PhpCsFixer\FixerDefinition\CodeSample;
  75445. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75446. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  75447. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  75448. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  75449. use PhpCsFixer\Tokenizer\Token;
  75450. use PhpCsFixer\Tokenizer\Tokens;
  75451. /**
  75452. @phpstan-type
  75453. @phpstan-type
  75454. @implements
  75455. */
  75456. final class PhpUnitStrictFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  75457. {
  75458. /**
  75459. @use */
  75460. use ConfigurableFixerTrait;
  75461. private const ASSERTION_MAP = [
  75462. 'assertAttributeEquals' => 'assertAttributeSame',
  75463. 'assertAttributeNotEquals' => 'assertAttributeNotSame',
  75464. 'assertEquals' => 'assertSame',
  75465. 'assertNotEquals' => 'assertNotSame',
  75466. ];
  75467. public function getDefinition(): FixerDefinitionInterface
  75468. {
  75469. return new FixerDefinition(
  75470. 'PHPUnit methods like `assertSame` should be used instead of `assertEquals`.',
  75471. [
  75472. new CodeSample(
  75473. '<?php
  75474. final class MyTest extends \PHPUnit_Framework_TestCase
  75475. {
  75476. public function testSomeTest()
  75477. {
  75478. $this->assertAttributeEquals(a(), b());
  75479. $this->assertAttributeNotEquals(a(), b());
  75480. $this->assertEquals(a(), b());
  75481. $this->assertNotEquals(a(), b());
  75482. }
  75483. }
  75484. '
  75485. ),
  75486. new CodeSample(
  75487. '<?php
  75488. final class MyTest extends \PHPUnit_Framework_TestCase
  75489. {
  75490. public function testSomeTest()
  75491. {
  75492. $this->assertAttributeEquals(a(), b());
  75493. $this->assertAttributeNotEquals(a(), b());
  75494. $this->assertEquals(a(), b());
  75495. $this->assertNotEquals(a(), b());
  75496. }
  75497. }
  75498. ',
  75499. ['assertions' => ['assertEquals']]
  75500. ),
  75501. ],
  75502. null,
  75503. 'Risky when any of the functions are overridden or when testing object equality.'
  75504. );
  75505. }
  75506. public function isRisky(): bool
  75507. {
  75508. return true;
  75509. }
  75510. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  75511. {
  75512. $argumentsAnalyzer = new ArgumentsAnalyzer();
  75513. $functionsAnalyzer = new FunctionsAnalyzer();
  75514. foreach ($this->configuration['assertions'] as $methodBefore) {
  75515. $methodAfter = self::ASSERTION_MAP[$methodBefore];
  75516. for ($index = $startIndex; $index < $endIndex; ++$index) {
  75517. $methodIndex = $tokens->getNextTokenOfKind($index, [[T_STRING, $methodBefore]]);
  75518. if (null === $methodIndex) {
  75519. break;
  75520. }
  75521. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $methodIndex)) {
  75522. continue;
  75523. }
  75524. $openingParenthesisIndex = $tokens->getNextMeaningfulToken($methodIndex);
  75525. $argumentsCount = $argumentsAnalyzer->countArguments(
  75526. $tokens,
  75527. $openingParenthesisIndex,
  75528. $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesisIndex)
  75529. );
  75530. if (2 === $argumentsCount || 3 === $argumentsCount) {
  75531. $tokens[$methodIndex] = new Token([T_STRING, $methodAfter]);
  75532. }
  75533. $index = $methodIndex;
  75534. }
  75535. }
  75536. }
  75537. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  75538. {
  75539. return new FixerConfigurationResolver([
  75540. (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.'))
  75541. ->setAllowedTypes(['string[]'])
  75542. ->setAllowedValues([new AllowedValueSubset(array_keys(self::ASSERTION_MAP))])
  75543. ->setDefault([
  75544. 'assertAttributeEquals',
  75545. 'assertAttributeNotEquals',
  75546. 'assertEquals',
  75547. 'assertNotEquals',
  75548. ])
  75549. ->getOption(),
  75550. ]);
  75551. }
  75552. }
  75553. <?php
  75554. declare(strict_types=1);
  75555. namespace PhpCsFixer\Fixer\PhpUnit;
  75556. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  75557. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  75558. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  75559. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  75560. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  75561. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75562. use PhpCsFixer\FixerDefinition\CodeSample;
  75563. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75564. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  75565. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  75566. use PhpCsFixer\Tokenizer\CT;
  75567. use PhpCsFixer\Tokenizer\Token;
  75568. use PhpCsFixer\Tokenizer\Tokens;
  75569. /**
  75570. @phpstan-type
  75571. @phpstan-type
  75572. @implements
  75573. */
  75574. final class PhpUnitDedicateAssertFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  75575. {
  75576. /**
  75577. @use */
  75578. use ConfigurableFixerTrait;
  75579. private const FIX_MAP = [
  75580. 'array_key_exists' => [
  75581. 'positive' => 'assertArrayHasKey',
  75582. 'negative' => 'assertArrayNotHasKey',
  75583. 'argument_count' => 2,
  75584. ],
  75585. 'empty' => [
  75586. 'positive' => 'assertEmpty',
  75587. 'negative' => 'assertNotEmpty',
  75588. ],
  75589. 'file_exists' => [
  75590. 'positive' => 'assertFileExists',
  75591. 'negative' => 'assertFileNotExists',
  75592. ],
  75593. 'is_array' => true,
  75594. 'is_bool' => true,
  75595. 'is_callable' => true,
  75596. 'is_dir' => [
  75597. 'positive' => 'assertDirectoryExists',
  75598. 'negative' => 'assertDirectoryNotExists',
  75599. ],
  75600. 'is_double' => true,
  75601. 'is_float' => true,
  75602. 'is_infinite' => [
  75603. 'positive' => 'assertInfinite',
  75604. 'negative' => 'assertFinite',
  75605. ],
  75606. 'is_int' => true,
  75607. 'is_integer' => true,
  75608. 'is_long' => true,
  75609. 'is_nan' => [
  75610. 'positive' => 'assertNan',
  75611. 'negative' => false,
  75612. ],
  75613. 'is_null' => [
  75614. 'positive' => 'assertNull',
  75615. 'negative' => 'assertNotNull',
  75616. ],
  75617. 'is_numeric' => true,
  75618. 'is_object' => true,
  75619. 'is_readable' => [
  75620. 'positive' => 'assertIsReadable',
  75621. 'negative' => 'assertNotIsReadable',
  75622. ],
  75623. 'is_real' => true,
  75624. 'is_resource' => true,
  75625. 'is_scalar' => true,
  75626. 'is_string' => true,
  75627. 'is_writable' => [
  75628. 'positive' => 'assertIsWritable',
  75629. 'negative' => 'assertNotIsWritable',
  75630. ],
  75631. 'str_contains' => [
  75632. 'positive' => 'assertStringContainsString',
  75633. 'negative' => 'assertStringNotContainsString',
  75634. 'argument_count' => 2,
  75635. 'swap_arguments' => true,
  75636. ],
  75637. 'str_ends_with' => [
  75638. 'positive' => 'assertStringEndsWith',
  75639. 'negative' => 'assertStringEndsNotWith',
  75640. 'argument_count' => 2,
  75641. 'swap_arguments' => true,
  75642. ],
  75643. 'str_starts_with' => [
  75644. 'positive' => 'assertStringStartsWith',
  75645. 'negative' => 'assertStringStartsNotWith',
  75646. 'argument_count' => 2,
  75647. 'swap_arguments' => true,
  75648. ],
  75649. ];
  75650. private array $functions = [];
  75651. public function isRisky(): bool
  75652. {
  75653. return true;
  75654. }
  75655. public function getDefinition(): FixerDefinitionInterface
  75656. {
  75657. return new FixerDefinition(
  75658. 'PHPUnit assertions like `assertInternalType`, `assertFileExists`, should be used over `assertTrue`.',
  75659. [
  75660. new CodeSample(
  75661. '<?php
  75662. final class MyTest extends \PHPUnit_Framework_TestCase
  75663. {
  75664. public function testSomeTest()
  75665. {
  75666. $this->assertTrue(is_float( $a), "my message");
  75667. $this->assertTrue(is_nan($a));
  75668. }
  75669. }
  75670. '
  75671. ),
  75672. new CodeSample(
  75673. '<?php
  75674. final class MyTest extends \PHPUnit_Framework_TestCase
  75675. {
  75676. public function testSomeTest()
  75677. {
  75678. $this->assertTrue(is_dir($a));
  75679. $this->assertTrue(is_writable($a));
  75680. $this->assertTrue(is_readable($a));
  75681. }
  75682. }
  75683. ',
  75684. ['target' => PhpUnitTargetVersion::VERSION_5_6]
  75685. ),
  75686. ],
  75687. null,
  75688. 'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
  75689. );
  75690. }
  75691. public function getPriority(): int
  75692. {
  75693. return -9;
  75694. }
  75695. protected function configurePostNormalisation(): void
  75696. {
  75697. $this->functions = [
  75698. 'array_key_exists',
  75699. 'file_exists',
  75700. 'is_null',
  75701. 'str_ends_with',
  75702. 'str_starts_with',
  75703. ];
  75704. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_3_5)) {
  75705. $this->functions = array_merge($this->functions, [
  75706. 'empty',
  75707. 'is_array',
  75708. 'is_bool',
  75709. 'is_boolean',
  75710. 'is_callable',
  75711. 'is_double',
  75712. 'is_float',
  75713. 'is_int',
  75714. 'is_integer',
  75715. 'is_long',
  75716. 'is_numeric',
  75717. 'is_object',
  75718. 'is_real',
  75719. 'is_scalar',
  75720. 'is_string',
  75721. ]);
  75722. }
  75723. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_0)) {
  75724. $this->functions = array_merge($this->functions, [
  75725. 'is_infinite',
  75726. 'is_nan',
  75727. ]);
  75728. }
  75729. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_6)) {
  75730. $this->functions = array_merge($this->functions, [
  75731. 'is_dir',
  75732. 'is_readable',
  75733. 'is_writable',
  75734. ]);
  75735. }
  75736. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_7_5)) {
  75737. $this->functions = array_merge($this->functions, [
  75738. 'str_contains',
  75739. ]);
  75740. }
  75741. }
  75742. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  75743. {
  75744. $argumentsAnalyzer = new ArgumentsAnalyzer();
  75745. foreach ($this->getPreviousAssertCall($tokens, $startIndex, $endIndex) as $assertCall) {
  75746. if (\in_array($assertCall['loweredName'], ['asserttrue', 'assertfalse'], true)) {
  75747. $this->fixAssertTrueFalse($tokens, $argumentsAnalyzer, $assertCall);
  75748. continue;
  75749. }
  75750. if (\in_array(
  75751. $assertCall['loweredName'],
  75752. ['assertsame', 'assertnotsame', 'assertequals', 'assertnotequals'],
  75753. true
  75754. )) {
  75755. $this->fixAssertSameEquals($tokens, $assertCall);
  75756. }
  75757. }
  75758. }
  75759. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  75760. {
  75761. return new FixerConfigurationResolver([
  75762. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  75763. ->setAllowedTypes(['string'])
  75764. ->setAllowedValues([
  75765. PhpUnitTargetVersion::VERSION_3_0,
  75766. PhpUnitTargetVersion::VERSION_3_5,
  75767. PhpUnitTargetVersion::VERSION_5_0,
  75768. PhpUnitTargetVersion::VERSION_5_6,
  75769. PhpUnitTargetVersion::VERSION_NEWEST,
  75770. ])
  75771. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  75772. ->getOption(),
  75773. ]);
  75774. }
  75775. private function fixAssertTrueFalse(Tokens $tokens, ArgumentsAnalyzer $argumentsAnalyzer, array $assertCall): void
  75776. {
  75777. $testDefaultNamespaceTokenIndex = null;
  75778. $testIndex = $tokens->getNextMeaningfulToken($assertCall['openBraceIndex']);
  75779. if (!$tokens[$testIndex]->isGivenKind([T_EMPTY, T_STRING])) {
  75780. if ($this->fixAssertTrueFalseInstanceof($tokens, $assertCall, $testIndex)) {
  75781. return;
  75782. }
  75783. if (!$tokens[$testIndex]->isGivenKind(T_NS_SEPARATOR)) {
  75784. return;
  75785. }
  75786. $testDefaultNamespaceTokenIndex = $testIndex;
  75787. $testIndex = $tokens->getNextMeaningfulToken($testIndex);
  75788. }
  75789. $testOpenIndex = $tokens->getNextMeaningfulToken($testIndex);
  75790. if (!$tokens[$testOpenIndex]->equals('(')) {
  75791. return;
  75792. }
  75793. $testCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $testOpenIndex);
  75794. $assertCallCloseIndex = $tokens->getNextMeaningfulToken($testCloseIndex);
  75795. if (!$tokens[$assertCallCloseIndex]->equalsAny([')', ','])) {
  75796. return;
  75797. }
  75798. $content = strtolower($tokens[$testIndex]->getContent());
  75799. if (!\in_array($content, $this->functions, true)) {
  75800. return;
  75801. }
  75802. $arguments = $argumentsAnalyzer->getArguments($tokens, $testOpenIndex, $testCloseIndex);
  75803. $isPositive = 'asserttrue' === $assertCall['loweredName'];
  75804. if (isset(self::FIX_MAP[$content]) && \is_array(self::FIX_MAP[$content])) {
  75805. $fixDetails = self::FIX_MAP[$content];
  75806. $expectedCount = $fixDetails['argument_count'] ?? 1;
  75807. if ($expectedCount !== \count($arguments)) {
  75808. return;
  75809. }
  75810. $isPositive = $isPositive ? 'positive' : 'negative';
  75811. if (false === $fixDetails[$isPositive]) {
  75812. return;
  75813. }
  75814. $tokens[$assertCall['index']] = new Token([T_STRING, $fixDetails[$isPositive]]);
  75815. $this->removeFunctionCall($tokens, $testDefaultNamespaceTokenIndex, $testIndex, $testOpenIndex, $testCloseIndex);
  75816. if ($fixDetails['swap_arguments'] ?? false) {
  75817. if (2 !== $expectedCount) {
  75818. throw new \RuntimeException('Can only swap two arguments, please update map or logic.');
  75819. }
  75820. $this->swapArguments($tokens, $arguments);
  75821. }
  75822. return;
  75823. }
  75824. if (1 !== \count($arguments)) {
  75825. return;
  75826. }
  75827. $type = substr($content, 3);
  75828. $tokens[$assertCall['index']] = new Token([T_STRING, $isPositive ? 'assertInternalType' : 'assertNotInternalType']);
  75829. $tokens[$testIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, "'".$type."'"]);
  75830. $tokens[$testOpenIndex] = new Token(',');
  75831. $tokens->clearTokenAndMergeSurroundingWhitespace($testCloseIndex);
  75832. $commaIndex = $tokens->getPrevMeaningfulToken($testCloseIndex);
  75833. if ($tokens[$commaIndex]->equals(',')) {
  75834. $tokens->removeTrailingWhitespace($commaIndex);
  75835. $tokens->clearAt($commaIndex);
  75836. }
  75837. if (!$tokens[$testOpenIndex + 1]->isWhitespace()) {
  75838. $tokens->insertAt($testOpenIndex + 1, new Token([T_WHITESPACE, ' ']));
  75839. }
  75840. if (null !== $testDefaultNamespaceTokenIndex) {
  75841. $tokens->clearTokenAndMergeSurroundingWhitespace($testDefaultNamespaceTokenIndex);
  75842. }
  75843. }
  75844. private function fixAssertTrueFalseInstanceof(Tokens $tokens, array $assertCall, int $testIndex): bool
  75845. {
  75846. $isPositiveAssertion = 'asserttrue' === $assertCall['loweredName'];
  75847. if ($tokens[$testIndex]->equals('!')) {
  75848. $variableIndex = $tokens->getNextMeaningfulToken($testIndex);
  75849. $isPositiveCondition = false;
  75850. } else {
  75851. $variableIndex = $testIndex;
  75852. $isPositiveCondition = true;
  75853. }
  75854. if (!$tokens[$variableIndex]->isGivenKind(T_VARIABLE)) {
  75855. return false;
  75856. }
  75857. $instanceOfIndex = $tokens->getNextMeaningfulToken($variableIndex);
  75858. if (!$tokens[$instanceOfIndex]->isGivenKind(T_INSTANCEOF)) {
  75859. return false;
  75860. }
  75861. $classEndIndex = $instanceOfIndex;
  75862. $classPartTokens = [];
  75863. do {
  75864. $classEndIndex = $tokens->getNextMeaningfulToken($classEndIndex);
  75865. $classPartTokens[] = $tokens[$classEndIndex];
  75866. } while ($tokens[$classEndIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_VARIABLE]));
  75867. if ($tokens[$classEndIndex]->equalsAny([',', ')'])) {
  75868. array_pop($classPartTokens);
  75869. $isInstanceOfVar = reset($classPartTokens)->isGivenKind(T_VARIABLE);
  75870. $insertIndex = $testIndex - 1;
  75871. $newTokens = [];
  75872. foreach ($classPartTokens as $token) {
  75873. $newTokens[++$insertIndex] = clone $token;
  75874. }
  75875. if (!$isInstanceOfVar) {
  75876. $newTokens[++$insertIndex] = new Token([T_DOUBLE_COLON, '::']);
  75877. $newTokens[++$insertIndex] = new Token([CT::T_CLASS_CONSTANT, 'class']);
  75878. }
  75879. $newTokens[++$insertIndex] = new Token(',');
  75880. $newTokens[++$insertIndex] = new Token([T_WHITESPACE, ' ']);
  75881. $newTokens[++$insertIndex] = clone $tokens[$variableIndex];
  75882. for ($i = $classEndIndex - 1; $i >= $testIndex; --$i) {
  75883. if (!$tokens[$i]->isComment()) {
  75884. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  75885. }
  75886. }
  75887. $name = $isPositiveAssertion && $isPositiveCondition || !$isPositiveAssertion && !$isPositiveCondition
  75888. ? 'assertInstanceOf'
  75889. : 'assertNotInstanceOf';
  75890. $tokens->insertSlices($newTokens);
  75891. $tokens[$assertCall['index']] = new Token([T_STRING, $name]);
  75892. }
  75893. return true;
  75894. }
  75895. private function fixAssertSameEquals(Tokens $tokens, array $assertCall): void
  75896. {
  75897. $expectedIndex = $tokens->getNextMeaningfulToken($assertCall['openBraceIndex']);
  75898. if ($tokens[$expectedIndex]->isGivenKind([T_VARIABLE])) {
  75899. if (!$tokens[$tokens->getNextMeaningfulToken($expectedIndex)]->equals(',')) {
  75900. return;
  75901. }
  75902. } elseif (!$tokens[$expectedIndex]->isGivenKind([T_LNUMBER, T_VARIABLE])) {
  75903. return;
  75904. }
  75905. $commaIndex = $tokens->getNextMeaningfulToken($expectedIndex);
  75906. if (!$tokens[$commaIndex]->equals(',')) {
  75907. return;
  75908. }
  75909. $countCallIndex = $tokens->getNextMeaningfulToken($commaIndex);
  75910. if ($tokens[$countCallIndex]->isGivenKind(T_NS_SEPARATOR)) {
  75911. $defaultNamespaceTokenIndex = $countCallIndex;
  75912. $countCallIndex = $tokens->getNextMeaningfulToken($countCallIndex);
  75913. } else {
  75914. $defaultNamespaceTokenIndex = null;
  75915. }
  75916. if (!$tokens[$countCallIndex]->isGivenKind(T_STRING)) {
  75917. return;
  75918. }
  75919. $lowerContent = strtolower($tokens[$countCallIndex]->getContent());
  75920. if (!\in_array($lowerContent, ['count', 'sizeof'], true)) {
  75921. return;
  75922. }
  75923. $countCallOpenBraceIndex = $tokens->getNextMeaningfulToken($countCallIndex);
  75924. if (!$tokens[$countCallOpenBraceIndex]->equals('(')) {
  75925. return;
  75926. }
  75927. $countCallCloseBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $countCallOpenBraceIndex);
  75928. $afterCountCallCloseBraceIndex = $tokens->getNextMeaningfulToken($countCallCloseBraceIndex);
  75929. if (!$tokens[$afterCountCallCloseBraceIndex]->equalsAny([')', ','])) {
  75930. return;
  75931. }
  75932. $this->removeFunctionCall(
  75933. $tokens,
  75934. $defaultNamespaceTokenIndex,
  75935. $countCallIndex,
  75936. $countCallOpenBraceIndex,
  75937. $countCallCloseBraceIndex
  75938. );
  75939. $tokens[$assertCall['index']] = new Token([
  75940. T_STRING,
  75941. false === strpos($assertCall['loweredName'], 'not', 6) ? 'assertCount' : 'assertNotCount',
  75942. ]);
  75943. }
  75944. private function removeFunctionCall(Tokens $tokens, ?int $callNSIndex, int $callIndex, int $openIndex, int $closeIndex): void
  75945. {
  75946. $tokens->clearTokenAndMergeSurroundingWhitespace($callIndex);
  75947. if (null !== $callNSIndex) {
  75948. $tokens->clearTokenAndMergeSurroundingWhitespace($callNSIndex);
  75949. }
  75950. $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
  75951. $commaIndex = $tokens->getPrevMeaningfulToken($closeIndex);
  75952. if ($tokens[$commaIndex]->equals(',')) {
  75953. $tokens->removeTrailingWhitespace($commaIndex);
  75954. $tokens->clearAt($commaIndex);
  75955. }
  75956. $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
  75957. }
  75958. private function swapArguments(Tokens $tokens, array $argumentsIndices): void
  75959. {
  75960. [$firstArgumentIndex, $secondArgumentIndex] = array_keys($argumentsIndices);
  75961. $firstArgumentEndIndex = $argumentsIndices[$firstArgumentIndex];
  75962. $secondArgumentEndIndex = $argumentsIndices[$secondArgumentIndex];
  75963. $firstClone = $this->cloneAndClearTokens($tokens, $firstArgumentIndex, $firstArgumentEndIndex);
  75964. $secondClone = $this->cloneAndClearTokens($tokens, $secondArgumentIndex, $secondArgumentEndIndex);
  75965. if (!$firstClone[0]->isWhitespace()) {
  75966. array_unshift($firstClone, new Token([T_WHITESPACE, ' ']));
  75967. }
  75968. $tokens->insertAt($secondArgumentIndex, $firstClone);
  75969. if ($secondClone[0]->isWhitespace()) {
  75970. array_shift($secondClone);
  75971. }
  75972. $tokens->insertAt($firstArgumentIndex, $secondClone);
  75973. }
  75974. private function cloneAndClearTokens(Tokens $tokens, int $start, int $end): array
  75975. {
  75976. $clone = [];
  75977. for ($i = $start; $i <= $end; ++$i) {
  75978. if ('' === $tokens[$i]->getContent()) {
  75979. continue;
  75980. }
  75981. $clone[] = clone $tokens[$i];
  75982. $tokens->clearAt($i);
  75983. }
  75984. return $clone;
  75985. }
  75986. }
  75987. <?php
  75988. declare(strict_types=1);
  75989. namespace PhpCsFixer\Fixer\PhpUnit;
  75990. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  75991. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  75992. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  75993. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  75994. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  75995. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  75996. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  75997. use PhpCsFixer\FixerDefinition\CodeSample;
  75998. use PhpCsFixer\FixerDefinition\FixerDefinition;
  75999. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  76000. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  76001. use PhpCsFixer\Tokenizer\Token;
  76002. use PhpCsFixer\Tokenizer\Tokens;
  76003. /**
  76004. @phpstan-type
  76005. @phpstan-type
  76006. @implements
  76007. */
  76008. final class PhpUnitConstructFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  76009. {
  76010. /**
  76011. @use */
  76012. use ConfigurableFixerTrait;
  76013. public function isRisky(): bool
  76014. {
  76015. return true;
  76016. }
  76017. public function getDefinition(): FixerDefinitionInterface
  76018. {
  76019. return new FixerDefinition(
  76020. 'PHPUnit assertion method calls like `->assertSame(true, $foo)` should be written with dedicated method like `->assertTrue($foo)`.',
  76021. [
  76022. new CodeSample(
  76023. '<?php
  76024. final class FooTest extends \PHPUnit_Framework_TestCase {
  76025. public function testSomething() {
  76026. $this->assertEquals(false, $b);
  76027. $this->assertSame(true, $a);
  76028. $this->assertNotEquals(null, $c);
  76029. $this->assertNotSame(null, $d);
  76030. }
  76031. }
  76032. '
  76033. ),
  76034. new CodeSample(
  76035. '<?php
  76036. final class FooTest extends \PHPUnit_Framework_TestCase {
  76037. public function testSomething() {
  76038. $this->assertEquals(false, $b);
  76039. $this->assertSame(true, $a);
  76040. $this->assertNotEquals(null, $c);
  76041. $this->assertNotSame(null, $d);
  76042. }
  76043. }
  76044. ',
  76045. ['assertions' => ['assertSame', 'assertNotSame']]
  76046. ),
  76047. ],
  76048. null,
  76049. 'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
  76050. );
  76051. }
  76052. public function getPriority(): int
  76053. {
  76054. return -8;
  76055. }
  76056. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  76057. {
  76058. if ([] === $this->configuration['assertions']) {
  76059. return;
  76060. }
  76061. foreach ($this->configuration['assertions'] as $assertionMethod) {
  76062. for ($index = $startIndex; $index < $endIndex; ++$index) {
  76063. $index = \call_user_func_array(
  76064. \in_array($assertionMethod, ['assertSame', 'assertEquals'], true)
  76065. ? [$this, 'fixAssertPositive']
  76066. : [$this, 'fixAssertNegative'],
  76067. [$tokens, $index, $assertionMethod]
  76068. );
  76069. if (null === $index) {
  76070. break;
  76071. }
  76072. }
  76073. }
  76074. }
  76075. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  76076. {
  76077. $assertMethods = [
  76078. 'assertEquals',
  76079. 'assertNotEquals',
  76080. 'assertNotSame',
  76081. 'assertSame',
  76082. ];
  76083. return new FixerConfigurationResolver([
  76084. (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.'))
  76085. ->setAllowedTypes(['string[]'])
  76086. ->setAllowedValues([new AllowedValueSubset($assertMethods)])
  76087. ->setDefault($assertMethods)
  76088. ->getOption(),
  76089. ]);
  76090. }
  76091. private function fixAssertNegative(Tokens $tokens, int $index, string $method): ?int
  76092. {
  76093. static $map = [
  76094. 'false' => 'assertNotFalse',
  76095. 'null' => 'assertNotNull',
  76096. 'true' => 'assertNotTrue',
  76097. ];
  76098. return $this->fixAssert($map, $tokens, $index, $method);
  76099. }
  76100. private function fixAssertPositive(Tokens $tokens, int $index, string $method): ?int
  76101. {
  76102. static $map = [
  76103. 'false' => 'assertFalse',
  76104. 'null' => 'assertNull',
  76105. 'true' => 'assertTrue',
  76106. ];
  76107. return $this->fixAssert($map, $tokens, $index, $method);
  76108. }
  76109. private function fixAssert(array $map, Tokens $tokens, int $index, string $method): ?int
  76110. {
  76111. $functionsAnalyzer = new FunctionsAnalyzer();
  76112. $sequence = $tokens->findSequence(
  76113. [
  76114. [T_STRING, $method],
  76115. '(',
  76116. ],
  76117. $index
  76118. );
  76119. if (null === $sequence) {
  76120. return null;
  76121. }
  76122. $sequenceIndices = array_keys($sequence);
  76123. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $sequenceIndices[0])) {
  76124. return null;
  76125. }
  76126. $sequenceIndices[2] = $tokens->getNextMeaningfulToken($sequenceIndices[1]);
  76127. $firstParameterToken = $tokens[$sequenceIndices[2]];
  76128. if (!$firstParameterToken->isNativeConstant()) {
  76129. return $sequenceIndices[2];
  76130. }
  76131. $sequenceIndices[3] = $tokens->getNextMeaningfulToken($sequenceIndices[2]);
  76132. if (!$tokens[$sequenceIndices[3]]->equals(',')) {
  76133. return $sequenceIndices[3];
  76134. }
  76135. $tokens[$sequenceIndices[0]] = new Token([T_STRING, $map[strtolower($firstParameterToken->getContent())]]);
  76136. $tokens->clearRange($sequenceIndices[2], $tokens->getNextNonWhitespace($sequenceIndices[3]) - 1);
  76137. return $sequenceIndices[3];
  76138. }
  76139. }
  76140. <?php
  76141. declare(strict_types=1);
  76142. namespace PhpCsFixer\Fixer\PhpUnit;
  76143. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  76144. use PhpCsFixer\FixerDefinition\CodeSample;
  76145. use PhpCsFixer\FixerDefinition\FixerDefinition;
  76146. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  76147. use PhpCsFixer\Tokenizer\Token;
  76148. use PhpCsFixer\Tokenizer\Tokens;
  76149. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  76150. final class PhpUnitSetUpTearDownVisibilityFixer extends AbstractPhpUnitFixer
  76151. {
  76152. public function getDefinition(): FixerDefinitionInterface
  76153. {
  76154. return new FixerDefinition(
  76155. 'Changes the visibility of the `setUp()` and `tearDown()` functions of PHPUnit to `protected`, to match the PHPUnit TestCase.',
  76156. [
  76157. new CodeSample(
  76158. '<?php
  76159. final class MyTest extends \PHPUnit_Framework_TestCase
  76160. {
  76161. private $hello;
  76162. public function setUp()
  76163. {
  76164. $this->hello = "hello";
  76165. }
  76166. public function tearDown()
  76167. {
  76168. $this->hello = null;
  76169. }
  76170. }
  76171. '
  76172. ),
  76173. ],
  76174. null,
  76175. 'This fixer may change functions named `setUp()` or `tearDown()` outside of PHPUnit tests, '
  76176. .'when a class is wrongly seen as a PHPUnit test.'
  76177. );
  76178. }
  76179. public function isRisky(): bool
  76180. {
  76181. return true;
  76182. }
  76183. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  76184. {
  76185. $counter = 0;
  76186. $tokensAnalyzer = new TokensAnalyzer($tokens);
  76187. $slicesToInsert = [];
  76188. for ($index = $startIndex + 1; $index < $endIndex; ++$index) {
  76189. if (2 === $counter) {
  76190. break;
  76191. }
  76192. if ($tokens[$index]->equals('{')) {
  76193. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  76194. continue;
  76195. }
  76196. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  76197. continue;
  76198. }
  76199. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  76200. $functionName = strtolower($tokens[$functionNameIndex]->getContent());
  76201. if ('setup' !== $functionName && 'teardown' !== $functionName) {
  76202. continue;
  76203. }
  76204. ++$counter;
  76205. $visibility = $tokensAnalyzer->getMethodAttributes($index)['visibility'];
  76206. if (T_PUBLIC === $visibility) {
  76207. $visibilityIndex = $tokens->getPrevTokenOfKind($index, [[T_PUBLIC]]);
  76208. $tokens[$visibilityIndex] = new Token([T_PROTECTED, 'protected']);
  76209. continue;
  76210. }
  76211. if (null === $visibility) {
  76212. $slicesToInsert[$index] = [new Token([T_PROTECTED, 'protected']), new Token([T_WHITESPACE, ' '])];
  76213. }
  76214. }
  76215. $tokens->insertSlices($slicesToInsert);
  76216. }
  76217. }
  76218. <?php
  76219. declare(strict_types=1);
  76220. namespace PhpCsFixer\Fixer\PhpUnit;
  76221. use PhpCsFixer\DocBlock\DocBlock;
  76222. use PhpCsFixer\DocBlock\Line;
  76223. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  76224. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  76225. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  76226. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  76227. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  76228. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  76229. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  76230. use PhpCsFixer\FixerDefinition\CodeSample;
  76231. use PhpCsFixer\FixerDefinition\FixerDefinition;
  76232. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  76233. use PhpCsFixer\Preg;
  76234. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  76235. use PhpCsFixer\Tokenizer\Token;
  76236. use PhpCsFixer\Tokenizer\Tokens;
  76237. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  76238. /**
  76239. @phpstan-type
  76240. @phpstan-type
  76241. @implements
  76242. */
  76243. final class PhpUnitTestAnnotationFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  76244. {
  76245. /**
  76246. @use */
  76247. use ConfigurableFixerTrait;
  76248. public function isRisky(): bool
  76249. {
  76250. return true;
  76251. }
  76252. public function getDefinition(): FixerDefinitionInterface
  76253. {
  76254. return new FixerDefinition(
  76255. 'Adds or removes @test annotations from tests, following configuration.',
  76256. [
  76257. new CodeSample('<?php
  76258. class Test extends \PhpUnit\FrameWork\TestCase
  76259. {
  76260. /**
  76261. * @test
  76262. */
  76263. public function itDoesSomething() {} }'.$this->whitespacesConfig->getLineEnding()),
  76264. new CodeSample('<?php
  76265. class Test extends \PhpUnit\FrameWork\TestCase
  76266. {
  76267. public function testItDoesSomething() {}}'.$this->whitespacesConfig->getLineEnding(), ['style' => 'annotation']),
  76268. ],
  76269. null,
  76270. 'This fixer may change the name of your tests, and could cause incompatibility with'
  76271. .' abstract classes or interfaces.'
  76272. );
  76273. }
  76274. public function getPriority(): int
  76275. {
  76276. return 10;
  76277. }
  76278. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  76279. {
  76280. if ('annotation' === $this->configuration['style']) {
  76281. $this->applyTestAnnotation($tokens, $startIndex, $endIndex);
  76282. } else {
  76283. $this->applyTestPrefix($tokens, $startIndex, $endIndex);
  76284. }
  76285. }
  76286. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  76287. {
  76288. return new FixerConfigurationResolver([
  76289. (new FixerOptionBuilder('style', 'Whether to use the @test annotation or not.'))
  76290. ->setAllowedValues(['prefix', 'annotation'])
  76291. ->setDefault('prefix')
  76292. ->getOption(),
  76293. ]);
  76294. }
  76295. private function applyTestAnnotation(Tokens $tokens, int $startIndex, int $endIndex): void
  76296. {
  76297. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  76298. if (!$this->isTestMethod($tokens, $i)) {
  76299. continue;
  76300. }
  76301. $functionNameIndex = $tokens->getNextMeaningfulToken($i);
  76302. $functionName = $tokens[$functionNameIndex]->getContent();
  76303. if ($this->hasTestPrefix($functionName) && !$this->hasProperTestAnnotation($tokens, $i)) {
  76304. $newFunctionName = $this->removeTestPrefix($functionName);
  76305. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  76306. }
  76307. $docBlockIndex = $this->getDocBlockIndex($tokens, $i);
  76308. if ($this->isPHPDoc($tokens, $docBlockIndex)) {
  76309. $lines = $this->updateDocBlock($tokens, $docBlockIndex);
  76310. $lines = $this->addTestAnnotation($lines, $tokens, $docBlockIndex);
  76311. $lines = implode('', $lines);
  76312. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  76313. } else {
  76314. $this->createDocBlock($tokens, $docBlockIndex);
  76315. }
  76316. }
  76317. }
  76318. private function applyTestPrefix(Tokens $tokens, int $startIndex, int $endIndex): void
  76319. {
  76320. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  76321. if (!$this->isTestMethod($tokens, $i)) {
  76322. continue;
  76323. }
  76324. $docBlockIndex = $this->getDocBlockIndex($tokens, $i);
  76325. if (!$this->isPHPDoc($tokens, $docBlockIndex)) {
  76326. continue;
  76327. }
  76328. $lines = $this->updateDocBlock($tokens, $docBlockIndex);
  76329. $lines = implode('', $lines);
  76330. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  76331. $functionNameIndex = $tokens->getNextMeaningfulToken($i);
  76332. $functionName = $tokens[$functionNameIndex]->getContent();
  76333. if ($this->hasTestPrefix($functionName)) {
  76334. continue;
  76335. }
  76336. $newFunctionName = $this->addTestPrefix($functionName);
  76337. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  76338. }
  76339. }
  76340. private function isTestMethod(Tokens $tokens, int $index): bool
  76341. {
  76342. if (!$this->isMethod($tokens, $index)) {
  76343. return false;
  76344. }
  76345. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  76346. $functionName = $tokens[$functionNameIndex]->getContent();
  76347. if ($this->hasTestPrefix($functionName)) {
  76348. return true;
  76349. }
  76350. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  76351. return
  76352. $this->isPHPDoc($tokens, $docBlockIndex)
  76353. && str_contains($tokens[$docBlockIndex]->getContent(), '@test');
  76354. }
  76355. private function isMethod(Tokens $tokens, int $index): bool
  76356. {
  76357. $tokensAnalyzer = new TokensAnalyzer($tokens);
  76358. return $tokens[$index]->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index);
  76359. }
  76360. private function hasTestPrefix(string $functionName): bool
  76361. {
  76362. return str_starts_with($functionName, 'test');
  76363. }
  76364. private function hasProperTestAnnotation(Tokens $tokens, int $index): bool
  76365. {
  76366. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  76367. $doc = $tokens[$docBlockIndex]->getContent();
  76368. return Preg::match('/\*\s+@test\b/', $doc);
  76369. }
  76370. private function removeTestPrefix(string $functionName): string
  76371. {
  76372. $remainder = Preg::replace('/^test(?=[A-Z_])_?/', '', $functionName);
  76373. if ('' === $remainder) {
  76374. return $functionName;
  76375. }
  76376. return lcfirst($remainder);
  76377. }
  76378. private function addTestPrefix(string $functionName): string
  76379. {
  76380. return 'test'.ucfirst($functionName);
  76381. }
  76382. private function createDocBlock(Tokens $tokens, int $docBlockIndex): void
  76383. {
  76384. $lineEnd = $this->whitespacesConfig->getLineEnding();
  76385. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  76386. $toInsert = [
  76387. new Token([T_DOC_COMMENT, '/**'.$lineEnd."{$originalIndent} * @test".$lineEnd."{$originalIndent} */"]),
  76388. new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
  76389. ];
  76390. $index = $tokens->getNextMeaningfulToken($docBlockIndex);
  76391. $tokens->insertAt($index, $toInsert);
  76392. }
  76393. private function updateDocBlock(Tokens $tokens, int $docBlockIndex): array
  76394. {
  76395. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  76396. $lines = $doc->getLines();
  76397. return $this->updateLines($lines, $tokens, $docBlockIndex);
  76398. }
  76399. private function updateLines(array $lines, Tokens $tokens, int $docBlockIndex): array
  76400. {
  76401. $needsAnnotation = 'annotation' === $this->configuration['style'];
  76402. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  76403. for ($i = 0; $i < \count($lines); ++$i) {
  76404. if ($needsAnnotation && ($lines[$i]->isTheStart() && $lines[$i]->isTheEnd())) {
  76405. if (!$this->doesDocBlockContainTest($doc)) {
  76406. $lines = $this->splitUpDocBlock($lines, $tokens, $docBlockIndex);
  76407. return $this->updateLines($lines, $tokens, $docBlockIndex);
  76408. }
  76409. }
  76410. if (!$needsAnnotation
  76411. && str_contains($lines[$i]->getContent(), ' @test')
  76412. && !str_contains($lines[$i]->getContent(), '@testWith')
  76413. && !str_contains($lines[$i]->getContent(), '@testdox')
  76414. ) {
  76415. $lines[$i] = new Line(str_replace(' @test', '', $lines[$i]->getContent()));
  76416. }
  76417. if (!str_contains($lines[$i]->getContent(), '@depends')) {
  76418. continue;
  76419. }
  76420. $lines[$i] = $this->updateDependsAnnotation($lines[$i]);
  76421. }
  76422. return $lines;
  76423. }
  76424. private function splitUpDocBlock(array $lines, Tokens $tokens, int $docBlockIndex): array
  76425. {
  76426. $lineContent = $this->getSingleLineDocBlockEntry($lines);
  76427. $lineEnd = $this->whitespacesConfig->getLineEnding();
  76428. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  76429. return [
  76430. new Line('/**'.$lineEnd),
  76431. new Line($originalIndent.' * '.$lineContent.$lineEnd),
  76432. new Line($originalIndent.' */'),
  76433. ];
  76434. }
  76435. private function getSingleLineDocBlockEntry(array $lines): string
  76436. {
  76437. $line = $lines[0];
  76438. $line = str_replace('*/', '', $line->getContent());
  76439. $line = trim($line);
  76440. $line = str_split($line);
  76441. $i = \count($line);
  76442. do {
  76443. --$i;
  76444. } while ('*' !== $line[$i] && '*' !== $line[$i - 1] && '/' !== $line[$i - 2]);
  76445. if (' ' === $line[$i]) {
  76446. ++$i;
  76447. }
  76448. $line = \array_slice($line, $i);
  76449. return implode('', $line);
  76450. }
  76451. private function updateDependsAnnotation(Line $line): Line
  76452. {
  76453. if ('annotation' === $this->configuration['style']) {
  76454. return $this->removeTestPrefixFromDependsAnnotation($line);
  76455. }
  76456. return $this->addTestPrefixToDependsAnnotation($line);
  76457. }
  76458. private function removeTestPrefixFromDependsAnnotation(Line $line): Line
  76459. {
  76460. $line = str_split($line->getContent());
  76461. $dependsIndex = $this->findWhereDependsFunctionNameStarts($line);
  76462. $dependsFunctionName = implode('', \array_slice($line, $dependsIndex));
  76463. if ($this->hasTestPrefix($dependsFunctionName)) {
  76464. $dependsFunctionName = $this->removeTestPrefix($dependsFunctionName);
  76465. }
  76466. array_splice($line, $dependsIndex);
  76467. return new Line(implode('', $line).$dependsFunctionName);
  76468. }
  76469. private function addTestPrefixToDependsAnnotation(Line $line): Line
  76470. {
  76471. $line = str_split($line->getContent());
  76472. $dependsIndex = $this->findWhereDependsFunctionNameStarts($line);
  76473. $dependsFunctionName = implode('', \array_slice($line, $dependsIndex));
  76474. if (!$this->hasTestPrefix($dependsFunctionName)) {
  76475. $dependsFunctionName = $this->addTestPrefix($dependsFunctionName);
  76476. }
  76477. array_splice($line, $dependsIndex);
  76478. return new Line(implode('', $line).$dependsFunctionName);
  76479. }
  76480. private function findWhereDependsFunctionNameStarts(array $line): int
  76481. {
  76482. $index = stripos(implode('', $line), '@depends') + 8;
  76483. while (' ' === $line[$index]) {
  76484. ++$index;
  76485. }
  76486. return $index;
  76487. }
  76488. private function addTestAnnotation(array $lines, Tokens $tokens, int $docBlockIndex): array
  76489. {
  76490. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  76491. if (!$this->doesDocBlockContainTest($doc)) {
  76492. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $docBlockIndex);
  76493. $lineEnd = $this->whitespacesConfig->getLineEnding();
  76494. array_splice($lines, -1, 0, [new Line($originalIndent.' *'.$lineEnd.$originalIndent.' * @test'.$lineEnd)]);
  76495. \assert(array_is_list($lines));
  76496. }
  76497. return $lines;
  76498. }
  76499. private function doesDocBlockContainTest(DocBlock $doc): bool
  76500. {
  76501. return 0 !== \count($doc->getAnnotationsOfType('test'));
  76502. }
  76503. }
  76504. <?php
  76505. declare(strict_types=1);
  76506. namespace PhpCsFixer\Fixer\PhpUnit;
  76507. use PhpCsFixer\DocBlock\Annotation;
  76508. use PhpCsFixer\DocBlock\DocBlock;
  76509. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  76510. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  76511. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  76512. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  76513. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  76514. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  76515. use PhpCsFixer\FixerDefinition\FixerDefinition;
  76516. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  76517. use PhpCsFixer\FixerDefinition\VersionSpecification;
  76518. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  76519. use PhpCsFixer\Preg;
  76520. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  76521. use PhpCsFixer\Tokenizer\Analyzer\FullyQualifiedNameAnalyzer;
  76522. use PhpCsFixer\Tokenizer\CT;
  76523. use PhpCsFixer\Tokenizer\Processor\ImportProcessor;
  76524. use PhpCsFixer\Tokenizer\Token;
  76525. use PhpCsFixer\Tokenizer\Tokens;
  76526. /**
  76527. @phpstan-type
  76528. @phpstan-type
  76529. @implements
  76530. */
  76531. final class PhpUnitAttributesFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  76532. {
  76533. /**
  76534. @use */
  76535. use ConfigurableFixerTrait;
  76536. private array $fixingMap;
  76537. public function __construct()
  76538. {
  76539. parent::__construct();
  76540. $this->prepareFixingMap();
  76541. }
  76542. public function getDefinition(): FixerDefinitionInterface
  76543. {
  76544. $codeSample = <<<'PHP'
  76545. <?php
  76546. /**
  76547. * @covers \VendorName\Foo
  76548. * @internal
  76549. */
  76550. final class FooTest extends TestCase {
  76551. /**
  76552. * @param int $expected
  76553. * @param int $actual
  76554. * @dataProvider giveMeSomeData
  76555. * @requires PHP 8.0
  76556. */
  76557. public function testSomething($expected, $actual) {}
  76558. }
  76559. PHP;
  76560. return new FixerDefinition(
  76561. 'PHPUnit attributes must be used over their respective PHPDoc-based annotations.',
  76562. [
  76563. new VersionSpecificCodeSample($codeSample, new VersionSpecification(8_00_00)),
  76564. new VersionSpecificCodeSample($codeSample, new VersionSpecification(8_00_00), ['keep_annotations' => true]),
  76565. ],
  76566. );
  76567. }
  76568. public function isCandidate(Tokens $tokens): bool
  76569. {
  76570. return \PHP_VERSION_ID >= 8_00_00 && parent::isCandidate($tokens);
  76571. }
  76572. public function getPriority(): int
  76573. {
  76574. return 8;
  76575. }
  76576. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  76577. {
  76578. return new FixerConfigurationResolver([
  76579. (new FixerOptionBuilder('keep_annotations', 'Whether to keep annotations or not. This may be helpful for projects that support PHP before version 8 or PHPUnit before version 10.'))
  76580. ->setAllowedTypes(['bool'])
  76581. ->setDefault(false)
  76582. ->getOption(),
  76583. ]);
  76584. }
  76585. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  76586. {
  76587. $fullyQualifiedNameAnalyzer = new FullyQualifiedNameAnalyzer($tokens);
  76588. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  76589. $docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
  76590. if ($tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT)) {
  76591. $startIndex = $docBlockIndex;
  76592. }
  76593. for ($index = $endIndex; $index >= $startIndex; --$index) {
  76594. if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  76595. continue;
  76596. }
  76597. $targetIndex = $tokens->getTokenNotOfKindSibling(
  76598. $index,
  76599. 1,
  76600. [[T_ABSTRACT], [T_COMMENT], [T_FINAL], [T_FUNCTION], [T_PRIVATE], [T_PROTECTED], [T_PUBLIC], [T_STATIC], [T_WHITESPACE]],
  76601. );
  76602. $annotationScope = $tokens[$targetIndex]->isGivenKind(T_CLASS) ? 'class' : 'method';
  76603. $docBlock = new DocBlock($tokens[$index]->getContent());
  76604. $presentAttributes = [];
  76605. foreach (array_reverse($docBlock->getAnnotations()) as $annotation) {
  76606. $annotationName = $annotation->getTag()->getName();
  76607. if (!isset($this->fixingMap[$annotationName])) {
  76608. continue;
  76609. }
  76610. if (!self::shouldBeFixed($annotationName, $annotationScope)) {
  76611. continue;
  76612. }
  76613. /**
  76614. @phpstan-ignore-next-line */
  76615. $tokensToInsert = self::{$this->fixingMap[$annotationName]}($tokens, $index, $annotation);
  76616. $presentAttributes[$annotationName] ??= self::isAttributeAlreadyPresent($fullyQualifiedNameAnalyzer, $tokens, $index, $tokensToInsert);
  76617. if ([] === $tokensToInsert) {
  76618. continue;
  76619. }
  76620. if (!$presentAttributes[$annotationName]) {
  76621. $tokens->insertSlices([$index + 1 => $tokensToInsert]);
  76622. }
  76623. if (!$this->configuration['keep_annotations']) {
  76624. $annotation->remove();
  76625. }
  76626. }
  76627. if ('' === $docBlock->getContent()) {
  76628. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  76629. } else {
  76630. $tokens[$index] = new Token([T_DOC_COMMENT, $docBlock->getContent()]);
  76631. }
  76632. }
  76633. }
  76634. private function prepareFixingMap(): void
  76635. {
  76636. foreach ([
  76637. 'after',
  76638. 'afterClass',
  76639. 'before',
  76640. 'beforeClass',
  76641. 'coversNothing',
  76642. 'doesNotPerformAssertions',
  76643. 'large',
  76644. 'medium',
  76645. 'runInSeparateProcess',
  76646. 'runTestsInSeparateProcesses',
  76647. 'small',
  76648. 'test',
  76649. 'preCondition',
  76650. 'postCondition',
  76651. ] as $annotation) {
  76652. $this->fixingMap[$annotation] = 'fixWithoutParameters';
  76653. }
  76654. foreach (['group', 'testDox', 'ticket'] as $annotation) {
  76655. $this->fixingMap[$annotation] = 'fixWithSingleStringValue';
  76656. }
  76657. foreach (['backupGlobals', 'backupStaticAttributes', 'preserveGlobalState'] as $annotation) {
  76658. $this->fixingMap[$annotation] = 'fixWithEnabledDisabledValue';
  76659. }
  76660. $this->fixingMap['covers'] = 'fixCovers';
  76661. $this->fixingMap['dataProvider'] = 'fixDataProvider';
  76662. $this->fixingMap['depends'] = 'fixDepends';
  76663. $this->fixingMap['requires'] = 'fixRequires';
  76664. $this->fixingMap['testWith'] = 'fixTestWith';
  76665. $this->fixingMap['uses'] = 'fixUses';
  76666. }
  76667. private static function shouldBeFixed(string $annotationName, string $annotationScope): bool
  76668. {
  76669. if (
  76670. 'method' === $annotationScope
  76671. && \in_array($annotationName, ['covers', 'large', 'medium', 'runTestsInSeparateProcesses', 'small', 'uses'], true)
  76672. ) {
  76673. return false;
  76674. }
  76675. if (
  76676. 'class' === $annotationScope
  76677. && \in_array($annotationName, ['after', 'afterClass', 'before', 'beforeClass', 'dataProvider', 'depends', 'postCondition', 'preCondition', 'runInSeparateProcess', 'test', 'testWith'], true)
  76678. ) {
  76679. return false;
  76680. }
  76681. return true;
  76682. }
  76683. private static function isAttributeAlreadyPresent(
  76684. FullyQualifiedNameAnalyzer $fullyQualifiedNameAnalyzer,
  76685. Tokens $tokens,
  76686. int $index,
  76687. array $tokensToInsert
  76688. ): bool {
  76689. $attributeIndex = $tokens->getNextMeaningfulToken($index);
  76690. if (!$tokens[$attributeIndex]->isGivenKind(T_ATTRIBUTE)) {
  76691. return false;
  76692. }
  76693. $insertedClassName = '';
  76694. foreach (\array_slice($tokensToInsert, 3) as $token) {
  76695. if ($token->equals('(') || $token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  76696. break;
  76697. }
  76698. $insertedClassName .= $token->getContent();
  76699. }
  76700. foreach (AttributeAnalyzer::collect($tokens, $attributeIndex) as $attributeAnalysis) {
  76701. foreach ($attributeAnalysis->getAttributes() as $attribute) {
  76702. $className = ltrim(AttributeAnalyzer::determineAttributeFullyQualifiedName($tokens, $attribute['name'], $attribute['start']), '\\');
  76703. if ($insertedClassName === $className) {
  76704. return true;
  76705. }
  76706. }
  76707. }
  76708. return false;
  76709. }
  76710. private static function fixWithoutParameters(Tokens $tokens, int $index, Annotation $annotation): array
  76711. {
  76712. return self::createAttributeTokens($tokens, $index, self::getAttributeNameForAnnotation($annotation));
  76713. }
  76714. private static function fixWithSingleStringValue(Tokens $tokens, int $index, Annotation $annotation): array
  76715. {
  76716. Preg::match(
  76717. \sprintf('/@%s\s+(.*\S)(?:\R|\s*\*+\/$)/', $annotation->getTag()->getName()),
  76718. $annotation->getContent(),
  76719. $matches,
  76720. );
  76721. if (!isset($matches[1])) {
  76722. return [];
  76723. }
  76724. return self::createAttributeTokens(
  76725. $tokens,
  76726. $index,
  76727. self::getAttributeNameForAnnotation($annotation),
  76728. self::createEscapedStringToken($matches[1]),
  76729. );
  76730. }
  76731. private static function fixWithEnabledDisabledValue(Tokens $tokens, int $index, Annotation $annotation): array
  76732. {
  76733. $matches = self::getMatches($annotation);
  76734. if (!isset($matches[1])) {
  76735. return [];
  76736. }
  76737. return self::createAttributeTokens(
  76738. $tokens,
  76739. $index,
  76740. self::getAttributeNameForAnnotation($annotation),
  76741. new Token([T_STRING, isset($matches[1]) && 'enabled' === $matches[1] ? 'true' : 'false']),
  76742. );
  76743. }
  76744. private static function fixCovers(Tokens $tokens, int $index, Annotation $annotation): array
  76745. {
  76746. $matches = self::getMatches($annotation);
  76747. \assert(isset($matches[1]));
  76748. if (str_starts_with($matches[1], '::')) {
  76749. return self::createAttributeTokens($tokens, $index, 'CoversFunction', self::createEscapedStringToken(substr($matches[1], 2)));
  76750. }
  76751. if (!str_contains($matches[1], '::')) {
  76752. return self::createAttributeTokens(
  76753. $tokens,
  76754. $index,
  76755. 'CoversClass',
  76756. ...self::toClassConstant($matches[1]),
  76757. );
  76758. }
  76759. return [];
  76760. }
  76761. private static function fixDataProvider(Tokens $tokens, int $index, Annotation $annotation): array
  76762. {
  76763. $matches = self::getMatches($annotation);
  76764. if (!isset($matches[1])) {
  76765. return [];
  76766. }
  76767. if (str_contains($matches[1], '::')) {
  76768. [$class, $method] = explode('::', $matches[1]);
  76769. return self::createAttributeTokens(
  76770. $tokens,
  76771. $index,
  76772. 'DataProviderExternal',
  76773. ...[
  76774. ...self::toClassConstant($class),
  76775. new Token(','),
  76776. new Token([T_WHITESPACE, ' ']),
  76777. self::fixNameAndCreateEscapedStringToken($method),
  76778. ],
  76779. );
  76780. }
  76781. return self::createAttributeTokens($tokens, $index, 'DataProvider', self::fixNameAndCreateEscapedStringToken($matches[1]));
  76782. }
  76783. private static function fixNameAndCreateEscapedStringToken(string $methodName): Token
  76784. {
  76785. return self::createEscapedStringToken(rtrim($methodName, " ()\n\r\t\v\x00"));
  76786. }
  76787. private static function fixDepends(Tokens $tokens, int $index, Annotation $annotation): array
  76788. {
  76789. $matches = self::getMatches($annotation);
  76790. if (!isset($matches[1])) {
  76791. return [];
  76792. }
  76793. $nameSuffix = '';
  76794. $depended = $matches[1];
  76795. if (isset($matches[2])) {
  76796. if ('clone' === $matches[1]) {
  76797. $nameSuffix = 'UsingDeepClone';
  76798. $depended = $matches[2];
  76799. } elseif ('shallowClone' === $matches[1]) {
  76800. $nameSuffix = 'UsingShallowClone';
  76801. $depended = $matches[2];
  76802. }
  76803. }
  76804. $class = null;
  76805. $method = $depended;
  76806. if (str_contains($depended, '::')) {
  76807. [$class, $method] = explode('::', $depended);
  76808. if ('class' === $method) {
  76809. $method = null;
  76810. $nameSuffix = '' === $nameSuffix ? 'OnClass' : ('OnClass'.$nameSuffix);
  76811. } else {
  76812. $nameSuffix = ('External'.$nameSuffix);
  76813. }
  76814. }
  76815. $attributeTokens = [];
  76816. if (null !== $class) {
  76817. $attributeTokens = self::toClassConstant($class);
  76818. }
  76819. if (null !== $method) {
  76820. if ([] !== $attributeTokens) {
  76821. $attributeTokens[] = new Token(',');
  76822. $attributeTokens[] = new Token([T_WHITESPACE, ' ']);
  76823. }
  76824. $attributeTokens[] = self::createEscapedStringToken($method);
  76825. }
  76826. return self::createAttributeTokens($tokens, $index, 'Depends'.$nameSuffix, ...$attributeTokens);
  76827. }
  76828. private static function fixRequires(Tokens $tokens, int $index, Annotation $annotation): array
  76829. {
  76830. $matches = self::getMatches($annotation);
  76831. if (!isset($matches[1])) {
  76832. return [];
  76833. }
  76834. $map = [
  76835. 'extension' => 'RequiresPhpExtension',
  76836. 'function' => 'RequiresFunction',
  76837. 'PHP' => 'RequiresPhp',
  76838. 'PHPUnit' => 'RequiresPhpunit',
  76839. 'OS' => 'RequiresOperatingSystem',
  76840. 'OSFAMILY' => 'RequiresOperatingSystemFamily',
  76841. 'setting' => 'RequiresSetting',
  76842. ];
  76843. if (!isset($matches[2]) || !isset($map[$matches[1]])) {
  76844. return [];
  76845. }
  76846. $attributeName = $map[$matches[1]];
  76847. if ('RequiresFunction' === $attributeName && str_contains($matches[2], '::')) {
  76848. [$class, $method] = explode('::', $matches[2]);
  76849. $attributeName = 'RequiresMethod';
  76850. $attributeTokens = [
  76851. ...self::toClassConstant($class),
  76852. new Token(','),
  76853. new Token([T_WHITESPACE, ' ']),
  76854. self::createEscapedStringToken($method),
  76855. ];
  76856. } elseif ('RequiresPhp' === $attributeName && isset($matches[3])) {
  76857. $attributeTokens = [self::createEscapedStringToken($matches[2].' '.$matches[3])];
  76858. } else {
  76859. $attributeTokens = [self::createEscapedStringToken(self::fixVersionConstraint($matches[2]))];
  76860. }
  76861. if (isset($matches[3]) && 'RequiresPhp' !== $attributeName) {
  76862. $attributeTokens[] = new Token(',');
  76863. $attributeTokens[] = new Token([T_WHITESPACE, ' ']);
  76864. $attributeTokens[] = self::createEscapedStringToken(self::fixVersionConstraint($matches[3]));
  76865. }
  76866. return self::createAttributeTokens($tokens, $index, $attributeName, ...$attributeTokens);
  76867. }
  76868. private static function fixVersionConstraint(string $version): string
  76869. {
  76870. if (Preg::match('/^[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?$/', $version)) {
  76871. $version = '>= '.$version;
  76872. }
  76873. return $version;
  76874. }
  76875. private static function fixTestWith(Tokens $tokens, int $index, Annotation $annotation): array
  76876. {
  76877. $content = $annotation->getContent();
  76878. $content = Preg::replace('/@testWith\s+/', '', $content);
  76879. $content = Preg::replace('/(^|\R)\s+\**\s*/', "\n", $content);
  76880. $content = trim($content);
  76881. if ('' === $content) {
  76882. return [];
  76883. }
  76884. $attributeTokens = [];
  76885. foreach (explode("\n", $content) as $json) {
  76886. $attributeTokens = array_merge(
  76887. $attributeTokens,
  76888. self::createAttributeTokens($tokens, $index, 'TestWithJson', self::createEscapedStringToken($json)),
  76889. );
  76890. }
  76891. return $attributeTokens;
  76892. }
  76893. private static function fixUses(Tokens $tokens, int $index, Annotation $annotation): array
  76894. {
  76895. $matches = self::getMatches($annotation);
  76896. if (!isset($matches[1])) {
  76897. return [];
  76898. }
  76899. if (str_starts_with($matches[1], '::')) {
  76900. $attributeName = 'UsesFunction';
  76901. $attributeTokens = [self::createEscapedStringToken(substr($matches[1], 2))];
  76902. } elseif (Preg::match('/^[a-zA-Z\d\\\]+$/', $matches[1])) {
  76903. $attributeName = 'UsesClass';
  76904. $attributeTokens = self::toClassConstant($matches[1]);
  76905. } else {
  76906. return [];
  76907. }
  76908. return self::createAttributeTokens($tokens, $index, $attributeName, ...$attributeTokens);
  76909. }
  76910. private static function getMatches(Annotation $annotation): array
  76911. {
  76912. Preg::match(
  76913. \sprintf('/@%s\s+(\S+)(?:\s+(\S+))?(?:\s+(.+\S))?\s*(?:\R|\*+\/$)/', $annotation->getTag()->getName()),
  76914. $annotation->getContent(),
  76915. $matches,
  76916. );
  76917. \assert(array_is_list($matches));
  76918. return $matches;
  76919. }
  76920. private static function getAttributeNameForAnnotation(Annotation $annotation): string
  76921. {
  76922. $annotationName = $annotation->getTag()->getName();
  76923. return 'backupStaticAttributes' === $annotationName
  76924. ? 'BackupStaticProperties'
  76925. : ucfirst($annotationName);
  76926. }
  76927. private static function createAttributeTokens(
  76928. Tokens $tokens,
  76929. int $index,
  76930. string $className,
  76931. Token ...$attributeTokens
  76932. ): array {
  76933. if ([] !== $attributeTokens) {
  76934. $attributeTokens = [
  76935. new Token('('),
  76936. ...$attributeTokens,
  76937. new Token(')'),
  76938. ];
  76939. }
  76940. return [
  76941. clone $tokens[$index + 1],
  76942. new Token([T_ATTRIBUTE, '#[']),
  76943. new Token([T_NS_SEPARATOR, '\\']),
  76944. new Token([T_STRING, 'PHPUnit']),
  76945. new Token([T_NS_SEPARATOR, '\\']),
  76946. new Token([T_STRING, 'Framework']),
  76947. new Token([T_NS_SEPARATOR, '\\']),
  76948. new Token([T_STRING, 'Attributes']),
  76949. new Token([T_NS_SEPARATOR, '\\']),
  76950. new Token([T_STRING, $className]),
  76951. ...$attributeTokens,
  76952. new Token([CT::T_ATTRIBUTE_CLOSE, ']']),
  76953. ];
  76954. }
  76955. private static function toClassConstant(string $name): array
  76956. {
  76957. return [
  76958. ...ImportProcessor::tokenizeName($name),
  76959. new Token([T_DOUBLE_COLON, '::']),
  76960. new Token([CT::T_CLASS_CONSTANT, 'class']),
  76961. ];
  76962. }
  76963. private static function createEscapedStringToken(string $value): Token
  76964. {
  76965. return new Token([T_CONSTANT_ENCAPSED_STRING, "'".str_replace("'", "\\'", $value)."'"]);
  76966. }
  76967. }
  76968. <?php
  76969. declare(strict_types=1);
  76970. namespace PhpCsFixer\Fixer\PhpUnit;
  76971. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  76972. use PhpCsFixer\FixerDefinition\CodeSample;
  76973. use PhpCsFixer\FixerDefinition\FixerDefinition;
  76974. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  76975. use PhpCsFixer\Tokenizer\Analyzer\DataProviderAnalyzer;
  76976. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  76977. use PhpCsFixer\Tokenizer\CT;
  76978. use PhpCsFixer\Tokenizer\Token;
  76979. use PhpCsFixer\Tokenizer\Tokens;
  76980. final class PhpUnitDataProviderReturnTypeFixer extends AbstractPhpUnitFixer
  76981. {
  76982. public function getDefinition(): FixerDefinitionInterface
  76983. {
  76984. return new FixerDefinition(
  76985. 'The return type of PHPUnit data provider must be `iterable`.',
  76986. [
  76987. new CodeSample(
  76988. '<?php
  76989. class FooTest extends TestCase {
  76990. /**
  76991. * @dataProvider provideSomethingCases
  76992. */
  76993. public function testSomething($expected, $actual) {}
  76994. public function provideSomethingCases(): array {}
  76995. }
  76996. ',
  76997. ),
  76998. new CodeSample(
  76999. '<?php
  77000. class FooTest extends TestCase {
  77001. /**
  77002. * @dataProvider provideSomethingCases
  77003. */
  77004. public function testSomething($expected, $actual) {}
  77005. public function provideSomethingCases() {}
  77006. }
  77007. ',
  77008. ),
  77009. ],
  77010. 'Data provider must return `iterable`, either an array of arrays or an object that implements the `Traversable` interface.',
  77011. 'Risky when relying on signature of the data provider.',
  77012. );
  77013. }
  77014. public function getPriority(): int
  77015. {
  77016. return 9;
  77017. }
  77018. public function isRisky(): bool
  77019. {
  77020. return true;
  77021. }
  77022. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77023. {
  77024. $dataProviderAnalyzer = new DataProviderAnalyzer();
  77025. $functionsAnalyzer = new FunctionsAnalyzer();
  77026. foreach (array_reverse($dataProviderAnalyzer->getDataProviders($tokens, $startIndex, $endIndex)) as $dataProviderAnalysis) {
  77027. $typeAnalysis = $functionsAnalyzer->getFunctionReturnType($tokens, $dataProviderAnalysis->getNameIndex());
  77028. if (null === $typeAnalysis) {
  77029. $argumentsStart = $tokens->getNextTokenOfKind($dataProviderAnalysis->getNameIndex(), ['(']);
  77030. $argumentsEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStart);
  77031. $tokens->insertAt(
  77032. $argumentsEnd + 1,
  77033. [
  77034. new Token([CT::T_TYPE_COLON, ':']),
  77035. new Token([T_WHITESPACE, ' ']),
  77036. new Token([T_STRING, 'iterable']),
  77037. ],
  77038. );
  77039. continue;
  77040. }
  77041. if ('iterable' === $typeAnalysis->getName()) {
  77042. continue;
  77043. }
  77044. $typeStartIndex = $tokens->getNextMeaningfulToken($typeAnalysis->getStartIndex() - 1);
  77045. $typeEndIndex = $typeAnalysis->getEndIndex();
  77046. if ($tokens->generatePartialCode($typeStartIndex, $typeEndIndex) !== $typeAnalysis->getName()) {
  77047. continue;
  77048. }
  77049. $tokens->overrideRange($typeStartIndex, $typeEndIndex, [new Token([T_STRING, 'iterable'])]);
  77050. }
  77051. }
  77052. }
  77053. <?php
  77054. declare(strict_types=1);
  77055. namespace PhpCsFixer\Fixer\PhpUnit;
  77056. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77057. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77058. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77059. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  77060. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77061. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77062. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77063. use PhpCsFixer\FixerDefinition\CodeSample;
  77064. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77065. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77066. use PhpCsFixer\Tokenizer\Tokens;
  77067. /**
  77068. @phpstan-type
  77069. @phpstan-type
  77070. @implements
  77071. */
  77072. final class PhpUnitSizeClassFixer extends AbstractPhpUnitFixer implements WhitespacesAwareFixerInterface, ConfigurableFixerInterface
  77073. {
  77074. /**
  77075. @use */
  77076. use ConfigurableFixerTrait;
  77077. private const SIZES = ['small', 'medium', 'large'];
  77078. public function getDefinition(): FixerDefinitionInterface
  77079. {
  77080. return new FixerDefinition(
  77081. 'All PHPUnit test cases should have `@small`, `@medium` or `@large` annotation to enable run time limits.',
  77082. [
  77083. new CodeSample("<?php\nclass MyTest extends TestCase {}\n"),
  77084. new CodeSample("<?php\nclass MyTest extends TestCase {}\n", ['group' => 'medium']),
  77085. ],
  77086. 'The special groups [small, medium, large] provides a way to identify tests that are taking long to be executed.'
  77087. );
  77088. }
  77089. public function getPriority(): int
  77090. {
  77091. return 9;
  77092. }
  77093. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77094. {
  77095. return new FixerConfigurationResolver([
  77096. (new FixerOptionBuilder('group', 'Define a specific group to be used in case no group is already in use.'))
  77097. ->setAllowedValues(self::SIZES)
  77098. ->setDefault('small')
  77099. ->getOption(),
  77100. ]);
  77101. }
  77102. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77103. {
  77104. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  77105. if ($this->isAbstractClass($tokens, $classIndex)) {
  77106. return;
  77107. }
  77108. $this->ensureIsDocBlockWithAnnotation(
  77109. $tokens,
  77110. $classIndex,
  77111. $this->configuration['group'],
  77112. self::SIZES,
  77113. [
  77114. 'phpunit\framework\attributes\small',
  77115. 'phpunit\framework\attributes\medium',
  77116. 'phpunit\framework\attributes\large',
  77117. ],
  77118. );
  77119. }
  77120. private function isAbstractClass(Tokens $tokens, int $i): bool
  77121. {
  77122. $typeIndex = $tokens->getPrevMeaningfulToken($i);
  77123. return $tokens[$typeIndex]->isGivenKind(T_ABSTRACT);
  77124. }
  77125. }
  77126. <?php
  77127. declare(strict_types=1);
  77128. namespace PhpCsFixer\Fixer\PhpUnit;
  77129. use PhpCsFixer\DocBlock\Annotation;
  77130. use PhpCsFixer\DocBlock\DocBlock;
  77131. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77132. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77133. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77134. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  77135. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77136. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77137. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77138. use PhpCsFixer\FixerDefinition\CodeSample;
  77139. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77140. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77141. use PhpCsFixer\Preg;
  77142. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  77143. use PhpCsFixer\Tokenizer\Token;
  77144. use PhpCsFixer\Tokenizer\Tokens;
  77145. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  77146. /**
  77147. @phpstan-type
  77148. @phpstan-type
  77149. @implements
  77150. */
  77151. final class PhpUnitNoExpectationAnnotationFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  77152. {
  77153. /**
  77154. @use */
  77155. use ConfigurableFixerTrait;
  77156. private bool $fixMessageRegExp;
  77157. public function getDefinition(): FixerDefinitionInterface
  77158. {
  77159. return new FixerDefinition(
  77160. 'Usages of `@expectedException*` annotations MUST be replaced by `->setExpectedException*` methods.',
  77161. [
  77162. new CodeSample(
  77163. '<?php
  77164. final class MyTest extends \PHPUnit_Framework_TestCase
  77165. {
  77166. /**
  77167. * @expectedException FooException
  77168. * @expectedExceptionMessageRegExp /foo.*$/
  77169. * @expectedExceptionCode 123
  77170. */
  77171. function testAaa()
  77172. {
  77173. aaa();
  77174. }
  77175. }
  77176. '
  77177. ),
  77178. new CodeSample(
  77179. '<?php
  77180. final class MyTest extends \PHPUnit_Framework_TestCase
  77181. {
  77182. /**
  77183. * @expectedException FooException
  77184. * @expectedExceptionCode 123
  77185. */
  77186. function testBbb()
  77187. {
  77188. bbb();
  77189. }
  77190. /**
  77191. * @expectedException FooException
  77192. * @expectedExceptionMessageRegExp /foo.*$/
  77193. */
  77194. function testCcc()
  77195. {
  77196. ccc();
  77197. }
  77198. }
  77199. ',
  77200. ['target' => PhpUnitTargetVersion::VERSION_3_2]
  77201. ),
  77202. ],
  77203. null,
  77204. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  77205. );
  77206. }
  77207. public function getPriority(): int
  77208. {
  77209. return 10;
  77210. }
  77211. public function isRisky(): bool
  77212. {
  77213. return true;
  77214. }
  77215. protected function configurePostNormalisation(): void
  77216. {
  77217. $this->fixMessageRegExp = PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_4_3);
  77218. }
  77219. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77220. {
  77221. return new FixerConfigurationResolver([
  77222. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  77223. ->setAllowedTypes(['string'])
  77224. ->setAllowedValues([PhpUnitTargetVersion::VERSION_3_2, PhpUnitTargetVersion::VERSION_4_3, PhpUnitTargetVersion::VERSION_NEWEST])
  77225. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  77226. ->getOption(),
  77227. (new FixerOptionBuilder('use_class_const', 'Use ::class notation.'))
  77228. ->setAllowedTypes(['bool'])
  77229. ->setDefault(true)
  77230. ->getOption(),
  77231. ]);
  77232. }
  77233. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77234. {
  77235. $tokensAnalyzer = new TokensAnalyzer($tokens);
  77236. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  77237. if (!$tokens[$i]->isGivenKind(T_FUNCTION) || $tokensAnalyzer->isLambda($i)) {
  77238. continue;
  77239. }
  77240. $functionIndex = $i;
  77241. $docBlockIndex = $i;
  77242. $braceIndex = $tokens->getNextTokenOfKind($functionIndex, [';', '{']);
  77243. if (!$tokens[$braceIndex]->equals('{')) {
  77244. continue;
  77245. }
  77246. do {
  77247. $docBlockIndex = $tokens->getPrevNonWhitespace($docBlockIndex);
  77248. } while ($tokens[$docBlockIndex]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT]));
  77249. if (!$tokens[$docBlockIndex]->isGivenKind(T_DOC_COMMENT)) {
  77250. continue;
  77251. }
  77252. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  77253. $annotations = [];
  77254. foreach ($doc->getAnnotationsOfType([
  77255. 'expectedException',
  77256. 'expectedExceptionCode',
  77257. 'expectedExceptionMessage',
  77258. 'expectedExceptionMessageRegExp',
  77259. ]) as $annotation) {
  77260. $tag = $annotation->getTag()->getName();
  77261. $content = $this->extractContentFromAnnotation($annotation);
  77262. $annotations[$tag] = $content;
  77263. $annotation->remove();
  77264. }
  77265. if (!isset($annotations['expectedException'])) {
  77266. continue;
  77267. }
  77268. if (!$this->fixMessageRegExp && isset($annotations['expectedExceptionMessageRegExp'])) {
  77269. continue;
  77270. }
  77271. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $docBlockIndex);
  77272. $paramList = $this->annotationsToParamList($annotations);
  77273. $newMethodsCode = '<?php $this->'
  77274. .(isset($annotations['expectedExceptionMessageRegExp']) ? 'setExpectedExceptionRegExp' : 'setExpectedException')
  77275. .'('
  77276. .implode(', ', $paramList)
  77277. .');';
  77278. $newMethods = Tokens::fromCode($newMethodsCode);
  77279. $newMethods[0] = new Token([
  77280. T_WHITESPACE,
  77281. $this->whitespacesConfig->getLineEnding().$originalIndent.$this->whitespacesConfig->getIndent(),
  77282. ]);
  77283. $docContent = $doc->getContent();
  77284. if ('' === $docContent) {
  77285. $docContent = '/** */';
  77286. }
  77287. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $docContent]);
  77288. $tokens->insertAt($braceIndex + 1, $newMethods);
  77289. $whitespaceIndex = $braceIndex + $newMethods->getSize() + 1;
  77290. $tokens[$whitespaceIndex] = new Token([
  77291. T_WHITESPACE,
  77292. $this->whitespacesConfig->getLineEnding().$tokens[$whitespaceIndex]->getContent(),
  77293. ]);
  77294. $i = $docBlockIndex;
  77295. }
  77296. }
  77297. private function extractContentFromAnnotation(Annotation $annotation): string
  77298. {
  77299. $tag = $annotation->getTag()->getName();
  77300. if (!Preg::match('/@'.$tag.'\s+(.+)$/s', $annotation->getContent(), $matches)) {
  77301. return '';
  77302. }
  77303. $content = Preg::replace('/\*+\/$/', '', $matches[1]);
  77304. if (Preg::match('/\R/u', $content)) {
  77305. $content = Preg::replace('/\s*\R+\s*\*\s*/u', ' ', $content);
  77306. }
  77307. return rtrim($content);
  77308. }
  77309. private function annotationsToParamList(array $annotations): array
  77310. {
  77311. $params = [];
  77312. $exceptionClass = ltrim($annotations['expectedException'], '\\');
  77313. if (str_contains($exceptionClass, '*')) {
  77314. $exceptionClass = substr($exceptionClass, 0, strpos($exceptionClass, '*'));
  77315. }
  77316. $exceptionClass = trim($exceptionClass);
  77317. if (true === $this->configuration['use_class_const']) {
  77318. $params[] = "\\{$exceptionClass}::class";
  77319. } else {
  77320. $params[] = "'{$exceptionClass}'";
  77321. }
  77322. if (isset($annotations['expectedExceptionMessage'])) {
  77323. $params[] = var_export($annotations['expectedExceptionMessage'], true);
  77324. } elseif (isset($annotations['expectedExceptionMessageRegExp'])) {
  77325. $params[] = var_export($annotations['expectedExceptionMessageRegExp'], true);
  77326. } elseif (isset($annotations['expectedExceptionCode'])) {
  77327. $params[] = 'null';
  77328. }
  77329. if (isset($annotations['expectedExceptionCode'])) {
  77330. $params[] = $annotations['expectedExceptionCode'];
  77331. }
  77332. return $params;
  77333. }
  77334. }
  77335. <?php
  77336. declare(strict_types=1);
  77337. namespace PhpCsFixer\Fixer\PhpUnit;
  77338. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77339. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77340. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77341. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77342. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77343. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77344. use PhpCsFixer\FixerDefinition\CodeSample;
  77345. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77346. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77347. use PhpCsFixer\Tokenizer\Token;
  77348. use PhpCsFixer\Tokenizer\Tokens;
  77349. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  77350. /**
  77351. @phpstan-type
  77352. @phpstan-type
  77353. @implements
  77354. */
  77355. final class PhpUnitDedicateAssertInternalTypeFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  77356. {
  77357. /**
  77358. @use */
  77359. use ConfigurableFixerTrait;
  77360. private array $typeToDedicatedAssertMap = [
  77361. 'array' => 'assertIsArray',
  77362. 'boolean' => 'assertIsBool',
  77363. 'bool' => 'assertIsBool',
  77364. 'double' => 'assertIsFloat',
  77365. 'float' => 'assertIsFloat',
  77366. 'integer' => 'assertIsInt',
  77367. 'int' => 'assertIsInt',
  77368. 'null' => 'assertNull',
  77369. 'numeric' => 'assertIsNumeric',
  77370. 'object' => 'assertIsObject',
  77371. 'real' => 'assertIsFloat',
  77372. 'resource' => 'assertIsResource',
  77373. 'string' => 'assertIsString',
  77374. 'scalar' => 'assertIsScalar',
  77375. 'callable' => 'assertIsCallable',
  77376. 'iterable' => 'assertIsIterable',
  77377. ];
  77378. public function getDefinition(): FixerDefinitionInterface
  77379. {
  77380. return new FixerDefinition(
  77381. 'PHPUnit assertions like `assertIsArray` should be used over `assertInternalType`.',
  77382. [
  77383. new CodeSample(
  77384. '<?php
  77385. final class MyTest extends \PHPUnit\Framework\TestCase
  77386. {
  77387. public function testMe()
  77388. {
  77389. $this->assertInternalType("array", $var);
  77390. $this->assertInternalType("boolean", $var);
  77391. }
  77392. }
  77393. '
  77394. ),
  77395. new CodeSample(
  77396. '<?php
  77397. final class MyTest extends \PHPUnit\Framework\TestCase
  77398. {
  77399. public function testMe()
  77400. {
  77401. $this->assertInternalType("array", $var);
  77402. $this->assertInternalType("boolean", $var);
  77403. }
  77404. }
  77405. ',
  77406. ['target' => PhpUnitTargetVersion::VERSION_7_5]
  77407. ),
  77408. ],
  77409. null,
  77410. 'Risky when PHPUnit methods are overridden or when project has PHPUnit incompatibilities.'
  77411. );
  77412. }
  77413. public function isRisky(): bool
  77414. {
  77415. return true;
  77416. }
  77417. public function getPriority(): int
  77418. {
  77419. return -16;
  77420. }
  77421. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77422. {
  77423. return new FixerConfigurationResolver([
  77424. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  77425. ->setAllowedTypes(['string'])
  77426. ->setAllowedValues([PhpUnitTargetVersion::VERSION_7_5, PhpUnitTargetVersion::VERSION_NEWEST])
  77427. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  77428. ->getOption(),
  77429. ]);
  77430. }
  77431. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77432. {
  77433. $anonymousClassIndices = [];
  77434. $tokenAnalyzer = new TokensAnalyzer($tokens);
  77435. for ($index = $startIndex; $index < $endIndex; ++$index) {
  77436. if (!$tokens[$index]->isGivenKind(T_CLASS) || !$tokenAnalyzer->isAnonymousClass($index)) {
  77437. continue;
  77438. }
  77439. $openingBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
  77440. $closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openingBraceIndex);
  77441. $anonymousClassIndices[$closingBraceIndex] = $openingBraceIndex;
  77442. }
  77443. for ($index = $endIndex - 1; $index > $startIndex; --$index) {
  77444. if (isset($anonymousClassIndices[$index])) {
  77445. $index = $anonymousClassIndices[$index];
  77446. continue;
  77447. }
  77448. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  77449. continue;
  77450. }
  77451. $functionName = strtolower($tokens[$index]->getContent());
  77452. if ('assertinternaltype' !== $functionName && 'assertnotinternaltype' !== $functionName) {
  77453. continue;
  77454. }
  77455. $bracketTokenIndex = $tokens->getNextMeaningfulToken($index);
  77456. if (!$tokens[$bracketTokenIndex]->equals('(')) {
  77457. continue;
  77458. }
  77459. $expectedTypeTokenIndex = $tokens->getNextMeaningfulToken($bracketTokenIndex);
  77460. $expectedTypeToken = $tokens[$expectedTypeTokenIndex];
  77461. if (!$expectedTypeToken->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  77462. continue;
  77463. }
  77464. $expectedType = trim($expectedTypeToken->getContent(), '\'"');
  77465. if (!isset($this->typeToDedicatedAssertMap[$expectedType])) {
  77466. continue;
  77467. }
  77468. $commaTokenIndex = $tokens->getNextMeaningfulToken($expectedTypeTokenIndex);
  77469. if (!$tokens[$commaTokenIndex]->equals(',')) {
  77470. continue;
  77471. }
  77472. $newAssertion = $this->typeToDedicatedAssertMap[$expectedType];
  77473. if ('assertnotinternaltype' === $functionName) {
  77474. $newAssertion = str_replace('Is', 'IsNot', $newAssertion);
  77475. $newAssertion = str_replace('Null', 'NotNull', $newAssertion);
  77476. }
  77477. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($commaTokenIndex);
  77478. $tokens->overrideRange($index, $nextMeaningfulTokenIndex - 1, [
  77479. new Token([T_STRING, $newAssertion]),
  77480. new Token('('),
  77481. ]);
  77482. }
  77483. }
  77484. }
  77485. <?php
  77486. declare(strict_types=1);
  77487. namespace PhpCsFixer\Fixer\PhpUnit;
  77488. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77489. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77490. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77491. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77492. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77493. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77494. use PhpCsFixer\FixerDefinition\CodeSample;
  77495. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77496. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77497. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  77498. use PhpCsFixer\Tokenizer\Token;
  77499. use PhpCsFixer\Tokenizer\Tokens;
  77500. /**
  77501. @phpstan-type
  77502. @phpstan-type
  77503. @implements
  77504. */
  77505. final class PhpUnitMockFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  77506. {
  77507. /**
  77508. @use */
  77509. use ConfigurableFixerTrait;
  77510. private bool $fixCreatePartialMock;
  77511. public function getDefinition(): FixerDefinitionInterface
  77512. {
  77513. return new FixerDefinition(
  77514. 'Usages of `->getMock` and `->getMockWithoutInvokingTheOriginalConstructor` methods MUST be replaced by `->createMock` or `->createPartialMock` methods.',
  77515. [
  77516. new CodeSample(
  77517. '<?php
  77518. final class MyTest extends \PHPUnit_Framework_TestCase
  77519. {
  77520. public function testFoo()
  77521. {
  77522. $mock = $this->getMockWithoutInvokingTheOriginalConstructor("Foo");
  77523. $mock1 = $this->getMock("Foo");
  77524. $mock1 = $this->getMock("Bar", ["aaa"]);
  77525. $mock1 = $this->getMock("Baz", ["aaa"], ["argument"]); // version with more than 2 params is not supported
  77526. }
  77527. }
  77528. '
  77529. ),
  77530. new CodeSample(
  77531. '<?php
  77532. final class MyTest extends \PHPUnit_Framework_TestCase
  77533. {
  77534. public function testFoo()
  77535. {
  77536. $mock1 = $this->getMock("Foo");
  77537. $mock1 = $this->getMock("Bar", ["aaa"]); // version with multiple params is not supported
  77538. }
  77539. }
  77540. ',
  77541. ['target' => PhpUnitTargetVersion::VERSION_5_4]
  77542. ),
  77543. ],
  77544. null,
  77545. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  77546. );
  77547. }
  77548. public function isRisky(): bool
  77549. {
  77550. return true;
  77551. }
  77552. protected function configurePostNormalisation(): void
  77553. {
  77554. $this->fixCreatePartialMock = PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_5);
  77555. }
  77556. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77557. {
  77558. $argumentsAnalyzer = new ArgumentsAnalyzer();
  77559. for ($index = $startIndex; $index < $endIndex; ++$index) {
  77560. if (!$tokens[$index]->isObjectOperator()) {
  77561. continue;
  77562. }
  77563. $index = $tokens->getNextMeaningfulToken($index);
  77564. if ($tokens[$index]->equals([T_STRING, 'getMockWithoutInvokingTheOriginalConstructor'], false)) {
  77565. $tokens[$index] = new Token([T_STRING, 'createMock']);
  77566. } elseif ($tokens[$index]->equals([T_STRING, 'getMock'], false)) {
  77567. $openingParenthesis = $tokens->getNextMeaningfulToken($index);
  77568. $closingParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesis);
  77569. $argumentsCount = $argumentsAnalyzer->countArguments($tokens, $openingParenthesis, $closingParenthesis);
  77570. if (1 === $argumentsCount) {
  77571. $tokens[$index] = new Token([T_STRING, 'createMock']);
  77572. } elseif (2 === $argumentsCount && true === $this->fixCreatePartialMock) {
  77573. $tokens[$index] = new Token([T_STRING, 'createPartialMock']);
  77574. }
  77575. }
  77576. }
  77577. }
  77578. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77579. {
  77580. return new FixerConfigurationResolver([
  77581. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  77582. ->setAllowedTypes(['string'])
  77583. ->setAllowedValues([PhpUnitTargetVersion::VERSION_5_4, PhpUnitTargetVersion::VERSION_5_5, PhpUnitTargetVersion::VERSION_NEWEST])
  77584. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  77585. ->getOption(),
  77586. ]);
  77587. }
  77588. }
  77589. <?php
  77590. declare(strict_types=1);
  77591. namespace PhpCsFixer\Fixer\PhpUnit;
  77592. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77593. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77594. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77595. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  77596. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  77597. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77598. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77599. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77600. use PhpCsFixer\FixerDefinition\CodeSample;
  77601. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77602. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77603. use PhpCsFixer\Tokenizer\Tokens;
  77604. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  77605. /**
  77606. @phpstan-type
  77607. @phpstan-type
  77608. @implements
  77609. */
  77610. final class PhpUnitInternalClassFixer extends AbstractPhpUnitFixer implements WhitespacesAwareFixerInterface, ConfigurableFixerInterface
  77611. {
  77612. /**
  77613. @use */
  77614. use ConfigurableFixerTrait;
  77615. public function getDefinition(): FixerDefinitionInterface
  77616. {
  77617. return new FixerDefinition(
  77618. 'All PHPUnit test classes should be marked as internal.',
  77619. [
  77620. new CodeSample("<?php\nclass MyTest extends TestCase {}\n"),
  77621. new CodeSample(
  77622. "<?php\nclass MyTest extends TestCase {}\nfinal class FinalTest extends TestCase {}\nabstract class AbstractTest extends TestCase {}\n",
  77623. ['types' => ['final']]
  77624. ),
  77625. ]
  77626. );
  77627. }
  77628. public function getPriority(): int
  77629. {
  77630. return 68;
  77631. }
  77632. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77633. {
  77634. $types = ['normal', 'final', 'abstract'];
  77635. return new FixerConfigurationResolver([
  77636. (new FixerOptionBuilder('types', 'What types of classes to mark as internal.'))
  77637. ->setAllowedValues([new AllowedValueSubset($types)])
  77638. ->setAllowedTypes(['string[]'])
  77639. ->setDefault(['normal', 'final'])
  77640. ->getOption(),
  77641. ]);
  77642. }
  77643. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77644. {
  77645. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  77646. $prevIndex = $tokens->getPrevMeaningfulToken($classIndex);
  77647. if ($tokens[$prevIndex]->isGivenKind(T_NEW)) {
  77648. return;
  77649. }
  77650. if (!$this->isAllowedByConfiguration($tokens, $classIndex)) {
  77651. return;
  77652. }
  77653. $this->ensureIsDocBlockWithAnnotation(
  77654. $tokens,
  77655. $classIndex,
  77656. 'internal',
  77657. ['internal'],
  77658. [],
  77659. );
  77660. }
  77661. private function isAllowedByConfiguration(Tokens $tokens, int $index): bool
  77662. {
  77663. $tokensAnalyzer = new TokensAnalyzer($tokens);
  77664. $modifiers = $tokensAnalyzer->getClassyModifiers($index);
  77665. if (isset($modifiers['final'])) {
  77666. return \in_array('final', $this->configuration['types'], true);
  77667. }
  77668. if (isset($modifiers['abstract'])) {
  77669. return \in_array('abstract', $this->configuration['types'], true);
  77670. }
  77671. return \in_array('normal', $this->configuration['types'], true);
  77672. }
  77673. }
  77674. <?php
  77675. declare(strict_types=1);
  77676. namespace PhpCsFixer\Fixer\PhpUnit;
  77677. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77678. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77679. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77680. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  77681. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77682. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77683. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77684. use PhpCsFixer\FixerDefinition\CodeSample;
  77685. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77686. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77687. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  77688. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  77689. use PhpCsFixer\Tokenizer\Token;
  77690. use PhpCsFixer\Tokenizer\Tokens;
  77691. /**
  77692. @phpstan-type
  77693. @phpstan-type
  77694. @implements
  77695. */
  77696. final class PhpUnitExpectationFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  77697. {
  77698. /**
  77699. @use */
  77700. use ConfigurableFixerTrait;
  77701. private array $methodMap = [];
  77702. public function getDefinition(): FixerDefinitionInterface
  77703. {
  77704. return new FixerDefinition(
  77705. 'Usages of `->setExpectedException*` methods MUST be replaced by `->expectException*` methods.',
  77706. [
  77707. new CodeSample(
  77708. '<?php
  77709. final class MyTest extends \PHPUnit_Framework_TestCase
  77710. {
  77711. public function testFoo()
  77712. {
  77713. $this->setExpectedException("RuntimeException", "Msg", 123);
  77714. foo();
  77715. }
  77716. public function testBar()
  77717. {
  77718. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  77719. bar();
  77720. }
  77721. }
  77722. '
  77723. ),
  77724. new CodeSample(
  77725. '<?php
  77726. final class MyTest extends \PHPUnit_Framework_TestCase
  77727. {
  77728. public function testFoo()
  77729. {
  77730. $this->setExpectedException("RuntimeException", null, 123);
  77731. foo();
  77732. }
  77733. public function testBar()
  77734. {
  77735. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  77736. bar();
  77737. }
  77738. }
  77739. ',
  77740. ['target' => PhpUnitTargetVersion::VERSION_8_4]
  77741. ),
  77742. new CodeSample(
  77743. '<?php
  77744. final class MyTest extends \PHPUnit_Framework_TestCase
  77745. {
  77746. public function testFoo()
  77747. {
  77748. $this->setExpectedException("RuntimeException", null, 123);
  77749. foo();
  77750. }
  77751. public function testBar()
  77752. {
  77753. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  77754. bar();
  77755. }
  77756. }
  77757. ',
  77758. ['target' => PhpUnitTargetVersion::VERSION_5_6]
  77759. ),
  77760. new CodeSample(
  77761. '<?php
  77762. final class MyTest extends \PHPUnit_Framework_TestCase
  77763. {
  77764. public function testFoo()
  77765. {
  77766. $this->setExpectedException("RuntimeException", "Msg", 123);
  77767. foo();
  77768. }
  77769. public function testBar()
  77770. {
  77771. $this->setExpectedExceptionRegExp("RuntimeException", "/Msg.*/", 123);
  77772. bar();
  77773. }
  77774. }
  77775. ',
  77776. ['target' => PhpUnitTargetVersion::VERSION_5_2]
  77777. ),
  77778. ],
  77779. null,
  77780. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  77781. );
  77782. }
  77783. public function getPriority(): int
  77784. {
  77785. return 0;
  77786. }
  77787. public function isRisky(): bool
  77788. {
  77789. return true;
  77790. }
  77791. protected function configurePostNormalisation(): void
  77792. {
  77793. $this->methodMap = [
  77794. 'setExpectedException' => 'expectExceptionMessage',
  77795. ];
  77796. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_6)) {
  77797. $this->methodMap['setExpectedExceptionRegExp'] = 'expectExceptionMessageRegExp';
  77798. }
  77799. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_8_4)) {
  77800. $this->methodMap['setExpectedExceptionRegExp'] = 'expectExceptionMessageMatches';
  77801. $this->methodMap['expectExceptionMessageRegExp'] = 'expectExceptionMessageMatches';
  77802. }
  77803. }
  77804. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  77805. {
  77806. return new FixerConfigurationResolver([
  77807. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  77808. ->setAllowedTypes(['string'])
  77809. ->setAllowedValues([PhpUnitTargetVersion::VERSION_5_2, PhpUnitTargetVersion::VERSION_5_6, PhpUnitTargetVersion::VERSION_8_4, PhpUnitTargetVersion::VERSION_NEWEST])
  77810. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  77811. ->getOption(),
  77812. ]);
  77813. }
  77814. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77815. {
  77816. foreach (Token::getObjectOperatorKinds() as $objectOperator) {
  77817. $this->applyPhpUnitClassFixWithObjectOperator($tokens, $startIndex, $endIndex, $objectOperator);
  77818. }
  77819. }
  77820. private function applyPhpUnitClassFixWithObjectOperator(Tokens $tokens, int $startIndex, int $endIndex, int $objectOperator): void
  77821. {
  77822. $argumentsAnalyzer = new ArgumentsAnalyzer();
  77823. $oldMethodSequence = [
  77824. [T_VARIABLE, '$this'],
  77825. [$objectOperator],
  77826. [T_STRING],
  77827. ];
  77828. for ($index = $startIndex; $startIndex < $endIndex; ++$index) {
  77829. $match = $tokens->findSequence($oldMethodSequence, $index);
  77830. if (null === $match) {
  77831. return;
  77832. }
  77833. [$thisIndex, , $index] = array_keys($match);
  77834. if (!isset($this->methodMap[$tokens[$index]->getContent()])) {
  77835. continue;
  77836. }
  77837. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  77838. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  77839. $commaIndex = $tokens->getPrevMeaningfulToken($closeIndex);
  77840. if ($tokens[$commaIndex]->equals(',')) {
  77841. $tokens->removeTrailingWhitespace($commaIndex);
  77842. $tokens->clearAt($commaIndex);
  77843. }
  77844. $arguments = $argumentsAnalyzer->getArguments($tokens, $openIndex, $closeIndex);
  77845. $argumentsCnt = \count($arguments);
  77846. $argumentsReplacements = ['expectException', $this->methodMap[$tokens[$index]->getContent()], 'expectExceptionCode'];
  77847. $indent = $this->whitespacesConfig->getLineEnding().WhitespacesAnalyzer::detectIndent($tokens, $thisIndex);
  77848. $isMultilineWhitespace = false;
  77849. for ($cnt = $argumentsCnt - 1; $cnt >= 1; --$cnt) {
  77850. $argStart = array_keys($arguments)[$cnt];
  77851. $argBefore = $tokens->getPrevMeaningfulToken($argStart);
  77852. if (!isset($argumentsReplacements[$cnt])) {
  77853. throw new \LogicException(\sprintf('Unexpected index %d to find replacement method.', $cnt));
  77854. }
  77855. if ('expectExceptionMessage' === $argumentsReplacements[$cnt]) {
  77856. $paramIndicatorIndex = $tokens->getNextMeaningfulToken($argBefore);
  77857. $afterParamIndicatorIndex = $tokens->getNextMeaningfulToken($paramIndicatorIndex);
  77858. if (
  77859. $tokens[$paramIndicatorIndex]->equals([T_STRING, 'null'], false)
  77860. && $tokens[$afterParamIndicatorIndex]->equals(')')
  77861. ) {
  77862. if ($tokens[$argBefore + 1]->isWhitespace()) {
  77863. $tokens->clearTokenAndMergeSurroundingWhitespace($argBefore + 1);
  77864. }
  77865. $tokens->clearTokenAndMergeSurroundingWhitespace($argBefore);
  77866. $tokens->clearTokenAndMergeSurroundingWhitespace($paramIndicatorIndex);
  77867. continue;
  77868. }
  77869. }
  77870. $isMultilineWhitespace = $isMultilineWhitespace || ($tokens[$argStart]->isWhitespace() && !$tokens[$argStart]->isWhitespace(" \t"));
  77871. $tokensOverrideArgStart = [
  77872. new Token([T_WHITESPACE, $indent]),
  77873. new Token([T_VARIABLE, '$this']),
  77874. new Token([T_OBJECT_OPERATOR, '->']),
  77875. new Token([T_STRING, $argumentsReplacements[$cnt]]),
  77876. new Token('('),
  77877. ];
  77878. $tokensOverrideArgBefore = [
  77879. new Token(')'),
  77880. new Token(';'),
  77881. ];
  77882. if ($isMultilineWhitespace) {
  77883. $tokensOverrideArgStart[] = new Token([T_WHITESPACE, $indent.$this->whitespacesConfig->getIndent()]);
  77884. array_unshift($tokensOverrideArgBefore, new Token([T_WHITESPACE, $indent]));
  77885. }
  77886. if ($tokens[$argStart]->isWhitespace()) {
  77887. $tokens->overrideRange($argStart, $argStart, $tokensOverrideArgStart);
  77888. } else {
  77889. $tokens->insertAt($argStart, $tokensOverrideArgStart);
  77890. }
  77891. $tokens->overrideRange($argBefore, $argBefore, $tokensOverrideArgBefore);
  77892. }
  77893. $methodName = 'expectException';
  77894. if ('expectExceptionMessageRegExp' === $tokens[$index]->getContent()) {
  77895. $methodName = $this->methodMap[$tokens[$index]->getContent()];
  77896. }
  77897. $tokens[$index] = new Token([T_STRING, $methodName]);
  77898. }
  77899. }
  77900. }
  77901. <?php
  77902. declare(strict_types=1);
  77903. namespace PhpCsFixer\Fixer\PhpUnit;
  77904. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77905. use PhpCsFixer\FixerDefinition\CodeSample;
  77906. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77907. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77908. use PhpCsFixer\Preg;
  77909. use PhpCsFixer\Tokenizer\Token;
  77910. use PhpCsFixer\Tokenizer\Tokens;
  77911. final class PhpUnitFqcnAnnotationFixer extends AbstractPhpUnitFixer
  77912. {
  77913. public function getDefinition(): FixerDefinitionInterface
  77914. {
  77915. return new FixerDefinition(
  77916. 'PHPUnit annotations should be a FQCNs including a root namespace.',
  77917. [new CodeSample(
  77918. '<?php
  77919. final class MyTest extends \PHPUnit_Framework_TestCase
  77920. {
  77921. /**
  77922. * @expectedException InvalidArgumentException
  77923. * @covers Project\NameSpace\Something
  77924. * @coversDefaultClass Project\Default
  77925. * @uses Project\Test\Util
  77926. */
  77927. public function testSomeTest()
  77928. {
  77929. }
  77930. }
  77931. '
  77932. )]
  77933. );
  77934. }
  77935. public function getPriority(): int
  77936. {
  77937. return -9;
  77938. }
  77939. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  77940. {
  77941. $prevDocCommentIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_DOC_COMMENT]]);
  77942. if (null !== $prevDocCommentIndex) {
  77943. $startIndex = $prevDocCommentIndex;
  77944. }
  77945. $this->fixPhpUnitClass($tokens, $startIndex, $endIndex);
  77946. }
  77947. private function fixPhpUnitClass(Tokens $tokens, int $startIndex, int $endIndex): void
  77948. {
  77949. for ($index = $startIndex; $index < $endIndex; ++$index) {
  77950. if ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  77951. $tokens[$index] = new Token([T_DOC_COMMENT, Preg::replace(
  77952. '~^(\s*\*\s*@(?:expectedException|covers|coversDefaultClass|uses)\h+)(?!(?:self|static)::)(\w.*)$~m',
  77953. '$1\\\$2',
  77954. $tokens[$index]->getContent()
  77955. )]);
  77956. }
  77957. }
  77958. }
  77959. }
  77960. <?php
  77961. declare(strict_types=1);
  77962. namespace PhpCsFixer\Fixer\PhpUnit;
  77963. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  77964. use PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer;
  77965. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  77966. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  77967. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  77968. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  77969. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  77970. use PhpCsFixer\FixerDefinition\CodeSample;
  77971. use PhpCsFixer\FixerDefinition\FixerDefinition;
  77972. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  77973. use PhpCsFixer\Tokenizer\Analyzer\DataProviderAnalyzer;
  77974. use PhpCsFixer\Tokenizer\Tokens;
  77975. /**
  77976. @phpstan-type
  77977. @phpstan-type
  77978. @implements
  77979. @phpstan-import-type
  77980. */
  77981. final class PhpUnitDataProviderMethodOrderFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  77982. {
  77983. /**
  77984. @use */
  77985. use ConfigurableFixerTrait;
  77986. public function getDefinition(): FixerDefinitionInterface
  77987. {
  77988. return new FixerDefinition(
  77989. 'Data provider method must be placed after/before the last/first test where used.',
  77990. [
  77991. new CodeSample(
  77992. '<?php
  77993. class FooTest extends TestCase {
  77994. public function dataProvider() {}
  77995. /**
  77996. * @dataProvider dataProvider
  77997. */
  77998. public function testSomething($expected, $actual) {}
  77999. }
  78000. ',
  78001. ),
  78002. new CodeSample(
  78003. '<?php
  78004. class FooTest extends TestCase {
  78005. /**
  78006. * @dataProvider dataProvider
  78007. */
  78008. public function testSomething($expected, $actual) {}
  78009. public function dataProvider() {}
  78010. }
  78011. ',
  78012. [
  78013. 'placement' => 'before',
  78014. ]
  78015. ),
  78016. ]
  78017. );
  78018. }
  78019. public function getPriority(): int
  78020. {
  78021. return 64;
  78022. }
  78023. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  78024. {
  78025. return new FixerConfigurationResolver([
  78026. (new FixerOptionBuilder('placement', 'Where to place the data provider relative to the test where used.'))
  78027. ->setAllowedValues(['after', 'before'])
  78028. ->setDefault('after')
  78029. ->getOption(),
  78030. ]);
  78031. }
  78032. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  78033. {
  78034. $elements = $this->getElements($tokens, $startIndex);
  78035. if (0 === \count($elements)) {
  78036. return;
  78037. }
  78038. $endIndex = $elements[array_key_last($elements)]['end'];
  78039. $dataProvidersWithUsagePairs = $this->getDataProvidersWithUsagePairs($tokens, $startIndex, $endIndex);
  78040. $origUsageDataProviderOrderPairs = $this->getOrigUsageDataProviderOrderPairs($dataProvidersWithUsagePairs);
  78041. $sorted = $elements;
  78042. $providersPlaced = [];
  78043. if ('before' === $this->configuration['placement']) {
  78044. foreach ($origUsageDataProviderOrderPairs as [$usageName, $providerName]) {
  78045. if (!isset($providersPlaced[$providerName])) {
  78046. $providersPlaced[$providerName] = true;
  78047. $sorted = $this->moveMethodElement($sorted, $usageName, $providerName, false);
  78048. }
  78049. }
  78050. } else {
  78051. $sameUsageName = false;
  78052. $sameProviderName = false;
  78053. foreach ($origUsageDataProviderOrderPairs as [$usageName, $providerName]) {
  78054. if (!isset($providersPlaced[$providerName])) {
  78055. $providersPlaced[$providerName] = true;
  78056. $sortedBefore = $sorted;
  78057. $sorted = $this->moveMethodElement(
  78058. $sorted,
  78059. $usageName === $sameUsageName
  78060. ? $sameProviderName
  78061. : $usageName,
  78062. $providerName,
  78063. true
  78064. );
  78065. $sameUsageName = $usageName;
  78066. $sameProviderName = $providerName;
  78067. if ($sortedBefore !== $sorted) {
  78068. unset($providersPlaced[$providerName]);
  78069. }
  78070. }
  78071. }
  78072. }
  78073. if ($sorted !== $elements) {
  78074. $this->sortTokens($tokens, $startIndex, $endIndex, $sorted);
  78075. }
  78076. }
  78077. private function getElements(Tokens $tokens, int $startIndex): array
  78078. {
  78079. $methodOrderFixer = new OrderedClassElementsFixer();
  78080. return \Closure::bind(static fn () => $methodOrderFixer->getElements($tokens, $startIndex), null, OrderedClassElementsFixer::class)();
  78081. }
  78082. private function sortTokens(Tokens $tokens, int $startIndex, int $endIndex, array $elements): void
  78083. {
  78084. $methodOrderFixer = new OrderedClassElementsFixer();
  78085. \Closure::bind(static fn () => $methodOrderFixer->sortTokens($tokens, $startIndex, $endIndex, $elements), null, OrderedClassElementsFixer::class)();
  78086. }
  78087. private function moveMethodElement(array $elements, string $nameKeep, string $nameToMove, bool $after): array
  78088. {
  78089. $i = 0;
  78090. $iKeep = false;
  78091. $iToMove = false;
  78092. foreach ($elements as $element) {
  78093. if ('method' === $element['type']) {
  78094. if ($element['name'] === $nameKeep) {
  78095. $iKeep = $i;
  78096. } elseif ($element['name'] === $nameToMove) {
  78097. $iToMove = $i;
  78098. }
  78099. }
  78100. ++$i;
  78101. }
  78102. \assert(false !== $iKeep);
  78103. \assert(false !== $iToMove);
  78104. if ($iToMove === $iKeep + ($after ? 1 : -1)) {
  78105. return $elements;
  78106. }
  78107. $elementToMove = $elements[$iToMove];
  78108. unset($elements[$iToMove]);
  78109. $c = $iKeep
  78110. + ($after ? 1 : 0)
  78111. + ($iToMove < $iKeep ? -1 : 0);
  78112. return [
  78113. ...\array_slice($elements, 0, $c),
  78114. $elementToMove,
  78115. ...\array_slice($elements, $c),
  78116. ];
  78117. }
  78118. private function getDataProvidersWithUsagePairs(Tokens $tokens, int $startIndex, int $endIndex): array
  78119. {
  78120. $dataProvidersWithUsagePairs = [];
  78121. $dataProviderAnalyzer = new DataProviderAnalyzer();
  78122. foreach ($dataProviderAnalyzer->getDataProviders($tokens, $startIndex, $endIndex) as $dataProviderAnalysis) {
  78123. $usages = [];
  78124. foreach ($dataProviderAnalysis->getUsageIndices() as $usageIndex) {
  78125. $methodNameTokens = $tokens->findSequence([[T_FUNCTION], [T_STRING]], $usageIndex[0], $endIndex);
  78126. if (null === $methodNameTokens) {
  78127. continue;
  78128. }
  78129. $usages[array_key_last($methodNameTokens)] = [
  78130. array_key_last($methodNameTokens),
  78131. end($methodNameTokens)->getContent(),
  78132. $usageIndex[1],
  78133. ];
  78134. }
  78135. \assert([] !== $usages);
  78136. $dataProvidersWithUsagePairs[] = [
  78137. [$dataProviderAnalysis->getNameIndex(), $dataProviderAnalysis->getName()],
  78138. $usages,
  78139. ];
  78140. }
  78141. return $dataProvidersWithUsagePairs;
  78142. }
  78143. private function getOrigUsageDataProviderOrderPairs(array $dataProvidersWithUsagePairs): array
  78144. {
  78145. $origUsagesOrderPairs = [];
  78146. foreach ($dataProvidersWithUsagePairs as [$dataProviderPair, $usagePairs]) {
  78147. foreach ($usagePairs as $usagePair) {
  78148. $origUsagesOrderPairs[] = [$usagePair, $dataProviderPair[1]];
  78149. }
  78150. }
  78151. uasort($origUsagesOrderPairs, static function (array $a, array $b): int {
  78152. $cmp = $a[0][0] <=> $b[0][0];
  78153. return 0 !== $cmp
  78154. ? $cmp
  78155. : $a[0][2] <=> $b[0][2];
  78156. });
  78157. $origUsageDataProviderOrderPairs = [];
  78158. foreach (array_map(static fn (array $v): array => [$v[0][1], $v[1]], $origUsagesOrderPairs) as [$usageName, $providerName]) {
  78159. $origUsageDataProviderOrderPairs[] = [$usageName, $providerName];
  78160. }
  78161. return $origUsageDataProviderOrderPairs;
  78162. }
  78163. }
  78164. <?php
  78165. declare(strict_types=1);
  78166. namespace PhpCsFixer\Fixer\PhpUnit;
  78167. use PhpCsFixer\AbstractFixer;
  78168. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  78169. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  78170. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  78171. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  78172. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  78173. use PhpCsFixer\FixerDefinition\CodeSample;
  78174. use PhpCsFixer\FixerDefinition\FixerDefinition;
  78175. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  78176. use PhpCsFixer\Preg;
  78177. use PhpCsFixer\Tokenizer\Analyzer\ClassyAnalyzer;
  78178. use PhpCsFixer\Tokenizer\Token;
  78179. use PhpCsFixer\Tokenizer\Tokens;
  78180. /**
  78181. @phpstan-type
  78182. @phpstan-type
  78183. @implements
  78184. */
  78185. final class PhpUnitNamespacedFixer extends AbstractFixer implements ConfigurableFixerInterface
  78186. {
  78187. /**
  78188. @use */
  78189. use ConfigurableFixerTrait;
  78190. private string $originalClassRegEx;
  78191. private array $classMap;
  78192. public function getDefinition(): FixerDefinitionInterface
  78193. {
  78194. $codeSample = '<?php
  78195. final class MyTest extends \PHPUnit_Framework_TestCase
  78196. {
  78197. public function testSomething()
  78198. {
  78199. PHPUnit_Framework_Assert::assertTrue(true);
  78200. }
  78201. }
  78202. ';
  78203. return new FixerDefinition(
  78204. 'PHPUnit classes MUST be used in namespaced version, e.g. `\PHPUnit\Framework\TestCase` instead of `\PHPUnit_Framework_TestCase`.',
  78205. [
  78206. new CodeSample($codeSample),
  78207. new CodeSample($codeSample, ['target' => PhpUnitTargetVersion::VERSION_4_8]),
  78208. ],
  78209. "PHPUnit v6 has finally fully switched to namespaces.\n"
  78210. ."You could start preparing the upgrade by switching from non-namespaced TestCase to namespaced one.\n"
  78211. .'Forward compatibility layer (`\PHPUnit\Framework\TestCase` class) was backported to PHPUnit v4.8.35 and PHPUnit v5.4.0.'."\n"
  78212. .'Extended forward compatibility layer (`PHPUnit\Framework\Assert`, `PHPUnit\Framework\BaseTestListener`, `PHPUnit\Framework\TestListener` classes) was introduced in v5.7.0.'."\n",
  78213. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  78214. );
  78215. }
  78216. public function isCandidate(Tokens $tokens): bool
  78217. {
  78218. return $tokens->isTokenKindFound(T_STRING);
  78219. }
  78220. public function getPriority(): int
  78221. {
  78222. return 2;
  78223. }
  78224. public function isRisky(): bool
  78225. {
  78226. return true;
  78227. }
  78228. protected function configurePostNormalisation(): void
  78229. {
  78230. if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_6_0)) {
  78231. $this->originalClassRegEx = '/^PHPUnit_\w+$/i';
  78232. $this->classMap = [
  78233. 'PHPUnit_Extensions_PhptTestCase' => 'PHPUnit\Runner\PhptTestCase',
  78234. 'PHPUnit_Framework_Constraint' => 'PHPUnit\Framework\Constraint\Constraint',
  78235. 'PHPUnit_Framework_Constraint_StringMatches' => 'PHPUnit\Framework\Constraint\StringMatchesFormatDescription',
  78236. 'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider' => 'PHPUnit\Framework\Constraint\JsonMatchesErrorMessageProvider',
  78237. 'PHPUnit_Framework_Constraint_PCREMatch' => 'PHPUnit\Framework\Constraint\RegularExpression',
  78238. 'PHPUnit_Framework_Constraint_ExceptionMessageRegExp' => 'PHPUnit\Framework\Constraint\ExceptionMessageRegularExpression',
  78239. 'PHPUnit_Framework_Constraint_And' => 'PHPUnit\Framework\Constraint\LogicalAnd',
  78240. 'PHPUnit_Framework_Constraint_Or' => 'PHPUnit\Framework\Constraint\LogicalOr',
  78241. 'PHPUnit_Framework_Constraint_Not' => 'PHPUnit\Framework\Constraint\LogicalNot',
  78242. 'PHPUnit_Framework_Constraint_Xor' => 'PHPUnit\Framework\Constraint\LogicalXor',
  78243. 'PHPUnit_Framework_Error' => 'PHPUnit\Framework\Error\Error',
  78244. 'PHPUnit_Framework_TestSuite_DataProvider' => 'PHPUnit\Framework\DataProviderTestSuite',
  78245. 'PHPUnit_Framework_MockObject_Invocation_Static' => 'PHPUnit\Framework\MockObject\Invocation\StaticInvocation',
  78246. 'PHPUnit_Framework_MockObject_Invocation_Object' => 'PHPUnit\Framework\MockObject\Invocation\ObjectInvocation',
  78247. 'PHPUnit_Framework_MockObject_Stub_Return' => 'PHPUnit\Framework\MockObject\Stub\ReturnStub',
  78248. 'PHPUnit_Runner_Filter_Group_Exclude' => 'PHPUnit\Runner\Filter\ExcludeGroupFilterIterator',
  78249. 'PHPUnit_Runner_Filter_Group_Include' => 'PHPUnit\Runner\Filter\IncludeGroupFilterIterator',
  78250. 'PHPUnit_Runner_Filter_Test' => 'PHPUnit\Runner\Filter\NameFilterIterator',
  78251. 'PHPUnit_Util_PHP' => 'PHPUnit\Util\PHP\AbstractPhpProcess',
  78252. 'PHPUnit_Util_PHP_Default' => 'PHPUnit\Util\PHP\DefaultPhpProcess',
  78253. 'PHPUnit_Util_PHP_Windows' => 'PHPUnit\Util\PHP\WindowsPhpProcess',
  78254. 'PHPUnit_Util_Regex' => 'PHPUnit\Util\RegularExpression',
  78255. 'PHPUnit_Util_TestDox_ResultPrinter_XML' => 'PHPUnit\Util\TestDox\XmlResultPrinter',
  78256. 'PHPUnit_Util_TestDox_ResultPrinter_HTML' => 'PHPUnit\Util\TestDox\HtmlResultPrinter',
  78257. 'PHPUnit_Util_TestDox_ResultPrinter_Text' => 'PHPUnit\Util\TestDox\TextResultPrinter',
  78258. 'PHPUnit_Util_TestSuiteIterator' => 'PHPUnit\Framework\TestSuiteIterator',
  78259. 'PHPUnit_Util_XML' => 'PHPUnit\Util\Xml',
  78260. ];
  78261. } elseif (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_7)) {
  78262. $this->originalClassRegEx = '/^PHPUnit_Framework_(TestCase|Assert|BaseTestListener|TestListener)+$/i';
  78263. $this->classMap = [];
  78264. } else {
  78265. $this->originalClassRegEx = '/^PHPUnit_Framework_TestCase$/i';
  78266. $this->classMap = [];
  78267. }
  78268. }
  78269. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  78270. {
  78271. $importedOriginalClassesMap = [];
  78272. $currIndex = 0;
  78273. while (true) {
  78274. $currIndex = $tokens->getNextTokenOfKind($currIndex, [[T_STRING]]);
  78275. if (null === $currIndex) {
  78276. break;
  78277. }
  78278. $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
  78279. if ($tokens[$prevIndex]->isGivenKind([T_CONST, T_DOUBLE_COLON])) {
  78280. continue;
  78281. }
  78282. $originalClass = $tokens[$currIndex]->getContent();
  78283. $allowedReplacementScenarios = (new ClassyAnalyzer())->isClassyInvocation($tokens, $currIndex)
  78284. || $this->isImport($tokens, $currIndex);
  78285. if (!$allowedReplacementScenarios || !Preg::match($this->originalClassRegEx, $originalClass)) {
  78286. ++$currIndex;
  78287. continue;
  78288. }
  78289. $substituteTokens = $this->generateReplacement($originalClass);
  78290. $tokens->clearAt($currIndex);
  78291. $tokens->insertAt(
  78292. $currIndex,
  78293. isset($importedOriginalClassesMap[$originalClass]) ? $substituteTokens[$substituteTokens->getSize() - 1] : $substituteTokens
  78294. );
  78295. $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
  78296. if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
  78297. $importedOriginalClassesMap[$originalClass] = true;
  78298. } elseif ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  78299. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  78300. if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
  78301. $importedOriginalClassesMap[$originalClass] = true;
  78302. }
  78303. }
  78304. }
  78305. }
  78306. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  78307. {
  78308. return new FixerConfigurationResolver([
  78309. (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
  78310. ->setAllowedTypes(['string'])
  78311. ->setAllowedValues([PhpUnitTargetVersion::VERSION_4_8, PhpUnitTargetVersion::VERSION_5_7, PhpUnitTargetVersion::VERSION_6_0, PhpUnitTargetVersion::VERSION_NEWEST])
  78312. ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
  78313. ->getOption(),
  78314. ]);
  78315. }
  78316. private function generateReplacement(string $originalClassName): Tokens
  78317. {
  78318. $delimiter = '_';
  78319. $string = $originalClassName;
  78320. $map = array_change_key_case($this->classMap);
  78321. if (isset($map[strtolower($originalClassName)])) {
  78322. $delimiter = '\\';
  78323. $string = $map[strtolower($originalClassName)];
  78324. }
  78325. $parts = explode($delimiter, $string);
  78326. $tokensArray = [];
  78327. while ([] !== $parts) {
  78328. $tokensArray[] = new Token([T_STRING, array_shift($parts)]);
  78329. if ([] !== $parts) {
  78330. $tokensArray[] = new Token([T_NS_SEPARATOR, '\\']);
  78331. }
  78332. }
  78333. return Tokens::fromArray($tokensArray);
  78334. }
  78335. private function isImport(Tokens $tokens, int $currIndex): bool
  78336. {
  78337. $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
  78338. if ($tokens[$prevIndex]->isGivenKind([T_NS_SEPARATOR])) {
  78339. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  78340. }
  78341. return $tokens[$prevIndex]->isGivenKind([T_USE]);
  78342. }
  78343. }
  78344. <?php
  78345. declare(strict_types=1);
  78346. namespace PhpCsFixer\Fixer\PhpUnit;
  78347. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  78348. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  78349. use PhpCsFixer\FixerDefinition\CodeSample;
  78350. use PhpCsFixer\FixerDefinition\FixerDefinition;
  78351. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  78352. use PhpCsFixer\Tokenizer\Tokens;
  78353. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  78354. final class PhpUnitTestClassRequiresCoversFixer extends AbstractPhpUnitFixer implements WhitespacesAwareFixerInterface
  78355. {
  78356. public function getDefinition(): FixerDefinitionInterface
  78357. {
  78358. return new FixerDefinition(
  78359. 'Adds a default `@coversNothing` annotation to PHPUnit test classes that have no `@covers*` annotation.',
  78360. [
  78361. new CodeSample(
  78362. '<?php
  78363. final class MyTest extends \PHPUnit_Framework_TestCase
  78364. {
  78365. public function testSomeTest()
  78366. {
  78367. $this->assertSame(a(), b());
  78368. }
  78369. }
  78370. '
  78371. ),
  78372. ]
  78373. );
  78374. }
  78375. public function getPriority(): int
  78376. {
  78377. return 9;
  78378. }
  78379. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  78380. {
  78381. $classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
  78382. $tokensAnalyzer = new TokensAnalyzer($tokens);
  78383. $modifiers = $tokensAnalyzer->getClassyModifiers($classIndex);
  78384. if (isset($modifiers['abstract'])) {
  78385. return;
  78386. }
  78387. $this->ensureIsDocBlockWithAnnotation(
  78388. $tokens,
  78389. $classIndex,
  78390. 'coversNothing',
  78391. [
  78392. 'covers',
  78393. 'coversDefaultClass',
  78394. 'coversNothing',
  78395. ],
  78396. [
  78397. 'phpunit\framework\attributes\coversclass',
  78398. 'phpunit\framework\attributes\coversnothing',
  78399. 'phpunit\framework\attributes\coversmethod',
  78400. 'phpunit\framework\attributes\coversfunction',
  78401. 'phpunit\framework\attributes\coverstrait',
  78402. ],
  78403. );
  78404. }
  78405. }
  78406. <?php
  78407. declare(strict_types=1);
  78408. namespace PhpCsFixer\Fixer\PhpUnit;
  78409. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  78410. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  78411. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  78412. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  78413. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  78414. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  78415. use PhpCsFixer\FixerDefinition\CodeSample;
  78416. use PhpCsFixer\FixerDefinition\FixerDefinition;
  78417. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  78418. use PhpCsFixer\Tokenizer\Analyzer\DataProviderAnalyzer;
  78419. use PhpCsFixer\Tokenizer\Token;
  78420. use PhpCsFixer\Tokenizer\Tokens;
  78421. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  78422. /**
  78423. @phpstan-type
  78424. @phpstan-type
  78425. @implements
  78426. */
  78427. final class PhpUnitDataProviderStaticFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  78428. {
  78429. /**
  78430. @use */
  78431. use ConfigurableFixerTrait;
  78432. public function getDefinition(): FixerDefinitionInterface
  78433. {
  78434. return new FixerDefinition(
  78435. 'Data providers must be static.',
  78436. [
  78437. new CodeSample(
  78438. '<?php
  78439. class FooTest extends TestCase {
  78440. /**
  78441. * @dataProvider provideSomethingCases
  78442. */
  78443. public function testSomething($expected, $actual) {}
  78444. public function provideSomethingCases() {}
  78445. }
  78446. '
  78447. ),
  78448. new CodeSample(
  78449. '<?php
  78450. class FooTest extends TestCase {
  78451. /**
  78452. * @dataProvider provideSomethingCases1
  78453. * @dataProvider provideSomethingCases2
  78454. */
  78455. public function testSomething($expected, $actual) {}
  78456. public function provideSomethingCases1() { $this->getData1(); }
  78457. public function provideSomethingCases2() { self::getData2(); }
  78458. }
  78459. ',
  78460. ['force' => true]
  78461. ),
  78462. new CodeSample(
  78463. '<?php
  78464. class FooTest extends TestCase {
  78465. /**
  78466. * @dataProvider provideSomething1Cases
  78467. * @dataProvider provideSomething2Cases
  78468. */
  78469. public function testSomething($expected, $actual) {}
  78470. public function provideSomething1Cases() { $this->getData1(); }
  78471. public function provideSomething2Cases() { self::getData2(); }
  78472. }
  78473. ',
  78474. ['force' => false]
  78475. ),
  78476. ],
  78477. null,
  78478. 'Fixer could be risky if one is calling data provider function dynamically.'
  78479. );
  78480. }
  78481. public function isRisky(): bool
  78482. {
  78483. return true;
  78484. }
  78485. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  78486. {
  78487. return new FixerConfigurationResolver([
  78488. (new FixerOptionBuilder(
  78489. 'force',
  78490. 'Whether to make the data providers static even if they have a dynamic class call'
  78491. .' (may introduce fatal error "using $this when not in object context",'
  78492. .' and you may have to adjust the code manually by converting dynamic calls to static ones).'
  78493. ))
  78494. ->setAllowedTypes(['bool'])
  78495. ->setDefault(false)
  78496. ->getOption(),
  78497. ]);
  78498. }
  78499. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  78500. {
  78501. $dataProviderAnalyzer = new DataProviderAnalyzer();
  78502. $tokensAnalyzer = new TokensAnalyzer($tokens);
  78503. $inserts = [];
  78504. foreach ($dataProviderAnalyzer->getDataProviders($tokens, $startIndex, $endIndex) as $dataProviderDefinitionIndex) {
  78505. $methodStartIndex = $tokens->getNextTokenOfKind($dataProviderDefinitionIndex->getNameIndex(), ['{']);
  78506. if (null !== $methodStartIndex) {
  78507. $methodEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $methodStartIndex);
  78508. if (false === $this->configuration['force'] && null !== $tokens->findSequence([[T_VARIABLE, '$this']], $methodStartIndex, $methodEndIndex)) {
  78509. continue;
  78510. }
  78511. }
  78512. $functionIndex = $tokens->getPrevTokenOfKind($dataProviderDefinitionIndex->getNameIndex(), [[T_FUNCTION]]);
  78513. $methodAttributes = $tokensAnalyzer->getMethodAttributes($functionIndex);
  78514. if (false !== $methodAttributes['static']) {
  78515. continue;
  78516. }
  78517. $inserts[$functionIndex] = [new Token([T_STATIC, 'static']), new Token([T_WHITESPACE, ' '])];
  78518. }
  78519. $tokens->insertSlices($inserts);
  78520. }
  78521. }
  78522. <?php
  78523. declare(strict_types=1);
  78524. namespace PhpCsFixer\Fixer\PhpUnit;
  78525. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  78526. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  78527. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  78528. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  78529. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  78530. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  78531. use PhpCsFixer\FixerDefinition\CodeSample;
  78532. use PhpCsFixer\FixerDefinition\FixerDefinition;
  78533. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  78534. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  78535. use PhpCsFixer\Tokenizer\CT;
  78536. use PhpCsFixer\Tokenizer\Token;
  78537. use PhpCsFixer\Tokenizer\Tokens;
  78538. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  78539. use PhpCsFixer\Utils;
  78540. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  78541. /**
  78542. @phpstan-type
  78543. @phpstan-type
  78544. @implements
  78545. */
  78546. final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  78547. {
  78548. /**
  78549. @use */
  78550. use ConfigurableFixerTrait;
  78551. public const CALL_TYPE_THIS = 'this';
  78552. public const CALL_TYPE_SELF = 'self';
  78553. public const CALL_TYPE_STATIC = 'static';
  78554. private const STATIC_METHODS = [
  78555. 'anything' => true,
  78556. 'arrayHasKey' => true,
  78557. 'assertArrayHasKey' => true,
  78558. 'assertArrayIsEqualToArrayIgnoringListOfKeys' => true,
  78559. 'assertArrayIsEqualToArrayOnlyConsideringListOfKeys' => true,
  78560. 'assertArrayIsIdenticalToArrayIgnoringListOfKeys' => true,
  78561. 'assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys' => true,
  78562. 'assertArrayNotHasKey' => true,
  78563. 'assertArraySubset' => true,
  78564. 'assertAttributeContains' => true,
  78565. 'assertAttributeContainsOnly' => true,
  78566. 'assertAttributeCount' => true,
  78567. 'assertAttributeEmpty' => true,
  78568. 'assertAttributeEquals' => true,
  78569. 'assertAttributeGreaterThan' => true,
  78570. 'assertAttributeGreaterThanOrEqual' => true,
  78571. 'assertAttributeInstanceOf' => true,
  78572. 'assertAttributeInternalType' => true,
  78573. 'assertAttributeLessThan' => true,
  78574. 'assertAttributeLessThanOrEqual' => true,
  78575. 'assertAttributeNotContains' => true,
  78576. 'assertAttributeNotContainsOnly' => true,
  78577. 'assertAttributeNotCount' => true,
  78578. 'assertAttributeNotEmpty' => true,
  78579. 'assertAttributeNotEquals' => true,
  78580. 'assertAttributeNotInstanceOf' => true,
  78581. 'assertAttributeNotInternalType' => true,
  78582. 'assertAttributeNotSame' => true,
  78583. 'assertAttributeSame' => true,
  78584. 'assertClassHasAttribute' => true,
  78585. 'assertClassHasStaticAttribute' => true,
  78586. 'assertClassNotHasAttribute' => true,
  78587. 'assertClassNotHasStaticAttribute' => true,
  78588. 'assertContains' => true,
  78589. 'assertContainsEquals' => true,
  78590. 'assertContainsNotOnlyArray' => true,
  78591. 'assertContainsNotOnlyBool' => true,
  78592. 'assertContainsNotOnlyCallable' => true,
  78593. 'assertContainsNotOnlyClosedResource' => true,
  78594. 'assertContainsNotOnlyFloat' => true,
  78595. 'assertContainsNotOnlyInstancesOf' => true,
  78596. 'assertContainsNotOnlyInt' => true,
  78597. 'assertContainsNotOnlyIterable' => true,
  78598. 'assertContainsNotOnlyNull' => true,
  78599. 'assertContainsNotOnlyNumeric' => true,
  78600. 'assertContainsNotOnlyObject' => true,
  78601. 'assertContainsNotOnlyResource' => true,
  78602. 'assertContainsNotOnlyScalar' => true,
  78603. 'assertContainsNotOnlyString' => true,
  78604. 'assertContainsOnly' => true,
  78605. 'assertContainsOnlyArray' => true,
  78606. 'assertContainsOnlyBool' => true,
  78607. 'assertContainsOnlyCallable' => true,
  78608. 'assertContainsOnlyClosedResource' => true,
  78609. 'assertContainsOnlyFloat' => true,
  78610. 'assertContainsOnlyInstancesOf' => true,
  78611. 'assertContainsOnlyInt' => true,
  78612. 'assertContainsOnlyIterable' => true,
  78613. 'assertContainsOnlyNull' => true,
  78614. 'assertContainsOnlyNumeric' => true,
  78615. 'assertContainsOnlyObject' => true,
  78616. 'assertContainsOnlyResource' => true,
  78617. 'assertContainsOnlyScalar' => true,
  78618. 'assertContainsOnlyString' => true,
  78619. 'assertCount' => true,
  78620. 'assertDirectoryDoesNotExist' => true,
  78621. 'assertDirectoryExists' => true,
  78622. 'assertDirectoryIsNotReadable' => true,
  78623. 'assertDirectoryIsNotWritable' => true,
  78624. 'assertDirectoryIsReadable' => true,
  78625. 'assertDirectoryIsWritable' => true,
  78626. 'assertDirectoryNotExists' => true,
  78627. 'assertDirectoryNotIsReadable' => true,
  78628. 'assertDirectoryNotIsWritable' => true,
  78629. 'assertDoesNotMatchRegularExpression' => true,
  78630. 'assertEmpty' => true,
  78631. 'assertEquals' => true,
  78632. 'assertEqualsCanonicalizing' => true,
  78633. 'assertEqualsIgnoringCase' => true,
  78634. 'assertEqualsWithDelta' => true,
  78635. 'assertEqualXMLStructure' => true,
  78636. 'assertFalse' => true,
  78637. 'assertFileDoesNotExist' => true,
  78638. 'assertFileEquals' => true,
  78639. 'assertFileEqualsCanonicalizing' => true,
  78640. 'assertFileEqualsIgnoringCase' => true,
  78641. 'assertFileExists' => true,
  78642. 'assertFileIsNotReadable' => true,
  78643. 'assertFileIsNotWritable' => true,
  78644. 'assertFileIsReadable' => true,
  78645. 'assertFileIsWritable' => true,
  78646. 'assertFileMatchesFormat' => true,
  78647. 'assertFileMatchesFormatFile' => true,
  78648. 'assertFileNotEquals' => true,
  78649. 'assertFileNotEqualsCanonicalizing' => true,
  78650. 'assertFileNotEqualsIgnoringCase' => true,
  78651. 'assertFileNotExists' => true,
  78652. 'assertFileNotIsReadable' => true,
  78653. 'assertFileNotIsWritable' => true,
  78654. 'assertFinite' => true,
  78655. 'assertGreaterThan' => true,
  78656. 'assertGreaterThanOrEqual' => true,
  78657. 'assertInfinite' => true,
  78658. 'assertInstanceOf' => true,
  78659. 'assertInternalType' => true,
  78660. 'assertIsArray' => true,
  78661. 'assertIsBool' => true,
  78662. 'assertIsCallable' => true,
  78663. 'assertIsClosedResource' => true,
  78664. 'assertIsFloat' => true,
  78665. 'assertIsInt' => true,
  78666. 'assertIsIterable' => true,
  78667. 'assertIsList' => true,
  78668. 'assertIsNotArray' => true,
  78669. 'assertIsNotBool' => true,
  78670. 'assertIsNotCallable' => true,
  78671. 'assertIsNotClosedResource' => true,
  78672. 'assertIsNotFloat' => true,
  78673. 'assertIsNotInt' => true,
  78674. 'assertIsNotIterable' => true,
  78675. 'assertIsNotNumeric' => true,
  78676. 'assertIsNotObject' => true,
  78677. 'assertIsNotReadable' => true,
  78678. 'assertIsNotResource' => true,
  78679. 'assertIsNotScalar' => true,
  78680. 'assertIsNotString' => true,
  78681. 'assertIsNotWritable' => true,
  78682. 'assertIsNumeric' => true,
  78683. 'assertIsObject' => true,
  78684. 'assertIsReadable' => true,
  78685. 'assertIsResource' => true,
  78686. 'assertIsScalar' => true,
  78687. 'assertIsString' => true,
  78688. 'assertIsWritable' => true,
  78689. 'assertJson' => true,
  78690. 'assertJsonFileEqualsJsonFile' => true,
  78691. 'assertJsonFileNotEqualsJsonFile' => true,
  78692. 'assertJsonStringEqualsJsonFile' => true,
  78693. 'assertJsonStringEqualsJsonString' => true,
  78694. 'assertJsonStringNotEqualsJsonFile' => true,
  78695. 'assertJsonStringNotEqualsJsonString' => true,
  78696. 'assertLessThan' => true,
  78697. 'assertLessThanOrEqual' => true,
  78698. 'assertMatchesRegularExpression' => true,
  78699. 'assertNan' => true,
  78700. 'assertNotContains' => true,
  78701. 'assertNotContainsEquals' => true,
  78702. 'assertNotContainsOnly' => true,
  78703. 'assertNotCount' => true,
  78704. 'assertNotEmpty' => true,
  78705. 'assertNotEquals' => true,
  78706. 'assertNotEqualsCanonicalizing' => true,
  78707. 'assertNotEqualsIgnoringCase' => true,
  78708. 'assertNotEqualsWithDelta' => true,
  78709. 'assertNotFalse' => true,
  78710. 'assertNotInstanceOf' => true,
  78711. 'assertNotInternalType' => true,
  78712. 'assertNotIsReadable' => true,
  78713. 'assertNotIsWritable' => true,
  78714. 'assertNotNull' => true,
  78715. 'assertNotRegExp' => true,
  78716. 'assertNotSame' => true,
  78717. 'assertNotSameSize' => true,
  78718. 'assertNotTrue' => true,
  78719. 'assertNull' => true,
  78720. 'assertObjectEquals' => true,
  78721. 'assertObjectHasAttribute' => true,
  78722. 'assertObjectHasProperty' => true,
  78723. 'assertObjectNotEquals' => true,
  78724. 'assertObjectNotHasAttribute' => true,
  78725. 'assertObjectNotHasProperty' => true,
  78726. 'assertRegExp' => true,
  78727. 'assertSame' => true,
  78728. 'assertSameSize' => true,
  78729. 'assertStringContainsString' => true,
  78730. 'assertStringContainsStringIgnoringCase' => true,
  78731. 'assertStringContainsStringIgnoringLineEndings' => true,
  78732. 'assertStringEndsNotWith' => true,
  78733. 'assertStringEndsWith' => true,
  78734. 'assertStringEqualsFile' => true,
  78735. 'assertStringEqualsFileCanonicalizing' => true,
  78736. 'assertStringEqualsFileIgnoringCase' => true,
  78737. 'assertStringEqualsStringIgnoringLineEndings' => true,
  78738. 'assertStringMatchesFormat' => true,
  78739. 'assertStringMatchesFormatFile' => true,
  78740. 'assertStringNotContainsString' => true,
  78741. 'assertStringNotContainsStringIgnoringCase' => true,
  78742. 'assertStringNotEqualsFile' => true,
  78743. 'assertStringNotEqualsFileCanonicalizing' => true,
  78744. 'assertStringNotEqualsFileIgnoringCase' => true,
  78745. 'assertStringNotMatchesFormat' => true,
  78746. 'assertStringNotMatchesFormatFile' => true,
  78747. 'assertStringStartsNotWith' => true,
  78748. 'assertStringStartsWith' => true,
  78749. 'assertThat' => true,
  78750. 'assertTrue' => true,
  78751. 'assertXmlFileEqualsXmlFile' => true,
  78752. 'assertXmlFileNotEqualsXmlFile' => true,
  78753. 'assertXmlStringEqualsXmlFile' => true,
  78754. 'assertXmlStringEqualsXmlString' => true,
  78755. 'assertXmlStringNotEqualsXmlFile' => true,
  78756. 'assertXmlStringNotEqualsXmlString' => true,
  78757. 'attribute' => true,
  78758. 'attributeEqualTo' => true,
  78759. 'callback' => true,
  78760. 'classHasAttribute' => true,
  78761. 'classHasStaticAttribute' => true,
  78762. 'contains' => true,
  78763. 'containsEqual' => true,
  78764. 'containsIdentical' => true,
  78765. 'containsOnly' => true,
  78766. 'containsOnlyArray' => true,
  78767. 'containsOnlyBool' => true,
  78768. 'containsOnlyCallable' => true,
  78769. 'containsOnlyClosedResource' => true,
  78770. 'containsOnlyFloat' => true,
  78771. 'containsOnlyInstancesOf' => true,
  78772. 'containsOnlyInt' => true,
  78773. 'containsOnlyIterable' => true,
  78774. 'containsOnlyNull' => true,
  78775. 'containsOnlyNumeric' => true,
  78776. 'containsOnlyObject' => true,
  78777. 'containsOnlyResource' => true,
  78778. 'containsOnlyScalar' => true,
  78779. 'containsOnlyString' => true,
  78780. 'countOf' => true,
  78781. 'directoryExists' => true,
  78782. 'equalTo' => true,
  78783. 'equalToCanonicalizing' => true,
  78784. 'equalToIgnoringCase' => true,
  78785. 'equalToWithDelta' => true,
  78786. 'fail' => true,
  78787. 'fileExists' => true,
  78788. 'getCount' => true,
  78789. 'getObjectAttribute' => true,
  78790. 'getStaticAttribute' => true,
  78791. 'greaterThan' => true,
  78792. 'greaterThanOrEqual' => true,
  78793. 'identicalTo' => true,
  78794. 'isArray' => true,
  78795. 'isBool' => true,
  78796. 'isCallable' => true,
  78797. 'isClosedResource' => true,
  78798. 'isEmpty' => true,
  78799. 'isFalse' => true,
  78800. 'isFinite' => true,
  78801. 'isFloat' => true,
  78802. 'isInfinite' => true,
  78803. 'isInstanceOf' => true,
  78804. 'isInt' => true,
  78805. 'isIterable' => true,
  78806. 'isJson' => true,
  78807. 'isList' => true,
  78808. 'isNan' => true,
  78809. 'isNull' => true,
  78810. 'isNumeric' => true,
  78811. 'isObject' => true,
  78812. 'isReadable' => true,
  78813. 'isResource' => true,
  78814. 'isScalar' => true,
  78815. 'isString' => true,
  78816. 'isTrue' => true,
  78817. 'isType' => true,
  78818. 'isWritable' => true,
  78819. 'lessThan' => true,
  78820. 'lessThanOrEqual' => true,
  78821. 'logicalAnd' => true,
  78822. 'logicalNot' => true,
  78823. 'logicalOr' => true,
  78824. 'logicalXor' => true,
  78825. 'markTestIncomplete' => true,
  78826. 'markTestSkipped' => true,
  78827. 'matches' => true,
  78828. 'matchesRegularExpression' => true,
  78829. 'objectEquals' => true,
  78830. 'objectHasAttribute' => true,
  78831. 'readAttribute' => true,
  78832. 'resetCount' => true,
  78833. 'stringContains' => true,
  78834. 'stringEndsWith' => true,
  78835. 'stringEqualsStringIgnoringLineEndings' => true,
  78836. 'stringStartsWith' => true,
  78837. 'any' => true,
  78838. 'at' => true,
  78839. 'atLeast' => true,
  78840. 'atLeastOnce' => true,
  78841. 'atMost' => true,
  78842. 'createStub' => true,
  78843. 'createConfiguredStub' => true,
  78844. 'createStubForIntersectionOfInterfaces' => true,
  78845. 'exactly' => true,
  78846. 'never' => true,
  78847. 'once' => true,
  78848. 'onConsecutiveCalls' => true,
  78849. 'returnArgument' => true,
  78850. 'returnCallback' => true,
  78851. 'returnSelf' => true,
  78852. 'returnValue' => true,
  78853. 'returnValueMap' => true,
  78854. 'setUpBeforeClass' => true,
  78855. 'tearDownAfterClass' => true,
  78856. 'throwException' => true,
  78857. ];
  78858. private const ALLOWED_VALUES = [
  78859. self::CALL_TYPE_THIS => true,
  78860. self::CALL_TYPE_SELF => true,
  78861. self::CALL_TYPE_STATIC => true,
  78862. ];
  78863. private array $conversionMap = [
  78864. self::CALL_TYPE_THIS => [[T_OBJECT_OPERATOR, '->'], [T_VARIABLE, '$this']],
  78865. self::CALL_TYPE_SELF => [[T_DOUBLE_COLON, '::'], [T_STRING, 'self']],
  78866. self::CALL_TYPE_STATIC => [[T_DOUBLE_COLON, '::'], [T_STATIC, 'static']],
  78867. ];
  78868. public function getDefinition(): FixerDefinitionInterface
  78869. {
  78870. $codeSample = '<?php
  78871. final class MyTest extends \PHPUnit_Framework_TestCase
  78872. {
  78873. public function testMe()
  78874. {
  78875. $this->assertSame(1, 2);
  78876. self::assertSame(1, 2);
  78877. static::assertSame(1, 2);
  78878. static::assertTrue(false);
  78879. }
  78880. }
  78881. ';
  78882. return new FixerDefinition(
  78883. 'Calls to `PHPUnit\Framework\TestCase` static methods must all be of the same type, either `$this->`, `self::` or `static::`.',
  78884. [
  78885. new CodeSample($codeSample),
  78886. new CodeSample($codeSample, ['call_type' => self::CALL_TYPE_THIS]),
  78887. new CodeSample($codeSample, ['methods' => ['assertTrue' => self::CALL_TYPE_THIS]]),
  78888. ],
  78889. null,
  78890. 'Risky when PHPUnit methods are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  78891. );
  78892. }
  78893. public function getPriority(): int
  78894. {
  78895. return 0;
  78896. }
  78897. public function isRisky(): bool
  78898. {
  78899. return true;
  78900. }
  78901. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  78902. {
  78903. return new FixerConfigurationResolver([
  78904. (new FixerOptionBuilder('call_type', 'The call type to use for referring to PHPUnit methods.'))
  78905. ->setAllowedTypes(['string'])
  78906. ->setAllowedValues(array_keys(self::ALLOWED_VALUES))
  78907. ->setDefault(self::CALL_TYPE_STATIC)
  78908. ->getOption(),
  78909. (new FixerOptionBuilder('methods', 'Dictionary of `method` => `call_type` values that differ from the default strategy.'))
  78910. ->setAllowedTypes(['array<string, string>'])
  78911. ->setAllowedValues([static function (array $option): bool {
  78912. foreach ($option as $method => $value) {
  78913. if (!isset(self::STATIC_METHODS[$method])) {
  78914. throw new InvalidOptionsException(
  78915. \sprintf(
  78916. 'Unexpected "methods" key, expected any of %s, got "%s".',
  78917. Utils::naturalLanguageJoin(array_keys(self::STATIC_METHODS)),
  78918. \gettype($method).'#'.$method
  78919. )
  78920. );
  78921. }
  78922. if (!isset(self::ALLOWED_VALUES[$value])) {
  78923. throw new InvalidOptionsException(
  78924. \sprintf(
  78925. 'Unexpected value for method "%s", expected any of %s, got "%s".',
  78926. $method,
  78927. Utils::naturalLanguageJoin(array_keys(self::ALLOWED_VALUES)),
  78928. \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value)
  78929. )
  78930. );
  78931. }
  78932. }
  78933. return true;
  78934. }])
  78935. ->setDefault([])
  78936. ->getOption(),
  78937. ]);
  78938. }
  78939. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  78940. {
  78941. $analyzer = new TokensAnalyzer($tokens);
  78942. for ($index = $startIndex; $index < $endIndex; ++$index) {
  78943. if ($tokens[$index]->isGivenKind(T_CLASS)) {
  78944. $index = $this->findEndOfNextBlock($tokens, $index);
  78945. continue;
  78946. }
  78947. $callType = $this->configuration['call_type'];
  78948. if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  78949. if ($analyzer->isLambda($index)) {
  78950. $index = $this->findEndOfNextBlock($tokens, $index);
  78951. continue;
  78952. }
  78953. if (self::CALL_TYPE_THIS === $callType) {
  78954. $attributes = $analyzer->getMethodAttributes($index);
  78955. if (false !== $attributes['static']) {
  78956. $index = $this->findEndOfNextBlock($tokens, $index);
  78957. continue;
  78958. }
  78959. }
  78960. }
  78961. if (!$tokens[$index]->isGivenKind(T_STRING) || !isset(self::STATIC_METHODS[$tokens[$index]->getContent()])) {
  78962. continue;
  78963. }
  78964. $nextIndex = $tokens->getNextMeaningfulToken($index);
  78965. if (!$tokens[$nextIndex]->equals('(')) {
  78966. $index = $nextIndex;
  78967. continue;
  78968. }
  78969. if ($tokens[$tokens->getNextMeaningfulToken($nextIndex)]->isGivenKind(CT::T_FIRST_CLASS_CALLABLE)) {
  78970. continue;
  78971. }
  78972. $methodName = $tokens[$index]->getContent();
  78973. if (isset($this->configuration['methods'][$methodName])) {
  78974. $callType = $this->configuration['methods'][$methodName];
  78975. }
  78976. $operatorIndex = $tokens->getPrevMeaningfulToken($index);
  78977. $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
  78978. if (!$this->needsConversion($tokens, $index, $referenceIndex, $callType)) {
  78979. continue;
  78980. }
  78981. $tokens[$operatorIndex] = new Token($this->conversionMap[$callType][0]);
  78982. $tokens[$referenceIndex] = new Token($this->conversionMap[$callType][1]);
  78983. }
  78984. }
  78985. private function needsConversion(Tokens $tokens, int $index, int $referenceIndex, string $callType): bool
  78986. {
  78987. $functionsAnalyzer = new FunctionsAnalyzer();
  78988. return $functionsAnalyzer->isTheSameClassCall($tokens, $index)
  78989. && !$tokens[$referenceIndex]->equals($this->conversionMap[$callType][1], false);
  78990. }
  78991. private function findEndOfNextBlock(Tokens $tokens, int $index): int
  78992. {
  78993. $nextIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  78994. return $tokens[$nextIndex]->equals('{')
  78995. ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nextIndex)
  78996. : $nextIndex;
  78997. }
  78998. }
  78999. <?php
  79000. declare(strict_types=1);
  79001. namespace PhpCsFixer\Fixer\PhpUnit;
  79002. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  79003. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  79004. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  79005. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  79006. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  79007. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  79008. use PhpCsFixer\FixerDefinition\CodeSample;
  79009. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79010. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79011. use PhpCsFixer\Preg;
  79012. use PhpCsFixer\Tokenizer\Analyzer\DataProviderAnalyzer;
  79013. use PhpCsFixer\Tokenizer\FCT;
  79014. use PhpCsFixer\Tokenizer\Token;
  79015. use PhpCsFixer\Tokenizer\Tokens;
  79016. /**
  79017. @phpstan-type
  79018. @phpstan-type
  79019. @implements
  79020. */
  79021. final class PhpUnitDataProviderNameFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  79022. {
  79023. /**
  79024. @use */
  79025. use ConfigurableFixerTrait;
  79026. public function getDefinition(): FixerDefinitionInterface
  79027. {
  79028. return new FixerDefinition(
  79029. 'Data provider names must match the name of the test.',
  79030. [
  79031. new CodeSample(
  79032. '<?php
  79033. class FooTest extends TestCase {
  79034. /**
  79035. * @dataProvider dataProvider
  79036. */
  79037. public function testSomething($expected, $actual) {}
  79038. public function dataProvider() {}
  79039. }
  79040. ',
  79041. ),
  79042. new CodeSample(
  79043. '<?php
  79044. class FooTest extends TestCase {
  79045. /**
  79046. * @dataProvider dt_prvdr_ftr
  79047. */
  79048. public function test_feature($expected, $actual) {}
  79049. public function dt_prvdr_ftr() {}
  79050. }
  79051. ',
  79052. [
  79053. 'prefix' => 'data_',
  79054. 'suffix' => '',
  79055. ]
  79056. ),
  79057. new CodeSample(
  79058. '<?php
  79059. class FooTest extends TestCase {
  79060. /**
  79061. * @dataProvider dataProviderUsedInMultipleTests
  79062. */
  79063. public function testA($expected, $actual) {}
  79064. /**
  79065. * @dataProvider dataProviderUsedInMultipleTests
  79066. */
  79067. public function testB($expected, $actual) {}
  79068. /**
  79069. * @dataProvider dataProviderUsedInSingleTest
  79070. */
  79071. public function testC($expected, $actual) {}
  79072. /**
  79073. * @dataProvider dataProviderUsedAsFirstInTest
  79074. * @dataProvider dataProviderUsedAsSecondInTest
  79075. */
  79076. public function testD($expected, $actual) {}
  79077. public function dataProviderUsedInMultipleTests() {}
  79078. public function dataProviderUsedInSingleTest() {}
  79079. public function dataProviderUsedAsFirstInTest() {}
  79080. public function dataProviderUsedAsSecondInTest() {}
  79081. }
  79082. ',
  79083. [
  79084. 'prefix' => 'provides',
  79085. 'suffix' => 'Data',
  79086. ]
  79087. ),
  79088. ],
  79089. null,
  79090. 'Fixer could be risky if one is calling data provider by name as function.'
  79091. );
  79092. }
  79093. public function isRisky(): bool
  79094. {
  79095. return true;
  79096. }
  79097. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  79098. {
  79099. return new FixerConfigurationResolver([
  79100. (new FixerOptionBuilder('prefix', 'Prefix that replaces "test".'))
  79101. ->setAllowedTypes(['string'])
  79102. ->setDefault('provide')
  79103. ->getOption(),
  79104. (new FixerOptionBuilder('suffix', 'Suffix to be present at the end.'))
  79105. ->setAllowedTypes(['string'])
  79106. ->setDefault('Cases')
  79107. ->getOption(),
  79108. ]);
  79109. }
  79110. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  79111. {
  79112. $dataProviderAnalyzer = new DataProviderAnalyzer();
  79113. foreach ($dataProviderAnalyzer->getDataProviders($tokens, $startIndex, $endIndex) as $dataProviderAnalysis) {
  79114. $testIndices = [];
  79115. foreach ($dataProviderAnalysis->getUsageIndices() as [$usageIndex]) {
  79116. $testIndices[$tokens->getNextTokenOfKind($usageIndex, [[T_FUNCTION]])] = $usageIndex;
  79117. }
  79118. if (\count($testIndices) > 1) {
  79119. continue;
  79120. }
  79121. $dataProviderNewName = $this->getDataProviderNameForUsageIndex($tokens, reset($testIndices));
  79122. if (null !== $tokens->findSequence([[T_FUNCTION], [T_STRING, $dataProviderNewName]], $startIndex, $endIndex)) {
  79123. continue;
  79124. }
  79125. foreach ($dataProviderAnalysis->getUsageIndices() as [$usageIndex]) {
  79126. if (substr_count($tokens[$usageIndex]->getContent(), '@dataProvider') > 1) {
  79127. continue;
  79128. }
  79129. $tokens[$dataProviderAnalysis->getNameIndex()] = new Token([T_STRING, $dataProviderNewName]);
  79130. $newCommentContent = $tokens[$usageIndex]->isGivenKind(T_DOC_COMMENT)
  79131. ? Preg::replace(
  79132. \sprintf('/(@dataProvider\s+)%s/', $dataProviderAnalysis->getName()),
  79133. \sprintf('$1%s', $dataProviderNewName),
  79134. $tokens[$usageIndex]->getContent(),
  79135. )
  79136. : \sprintf('%1$s%2$s%1$s', $tokens[$usageIndex]->getContent()[0], $dataProviderNewName);
  79137. $tokens[$usageIndex] = new Token([$tokens[$usageIndex]->getId(), $newCommentContent]);
  79138. }
  79139. }
  79140. }
  79141. private function getDataProviderNameForUsageIndex(Tokens $tokens, int $index): string
  79142. {
  79143. do {
  79144. if ($tokens[$index]->isGivenKind(FCT::T_ATTRIBUTE)) {
  79145. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  79146. }
  79147. $index = $tokens->getNextMeaningfulToken($index);
  79148. } while (!$tokens[$index]->isGivenKind(T_STRING));
  79149. $name = $tokens[$index]->getContent();
  79150. $name = Preg::replace('/^test_*/i', '', $name);
  79151. if ('' === $this->configuration['prefix']) {
  79152. $name = lcfirst($name);
  79153. } elseif ('_' !== substr($this->configuration['prefix'], -1)) {
  79154. $name = ucfirst($name);
  79155. }
  79156. return $this->configuration['prefix'].$name.$this->configuration['suffix'];
  79157. }
  79158. }
  79159. <?php
  79160. declare(strict_types=1);
  79161. namespace PhpCsFixer\Fixer\PhpUnit;
  79162. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  79163. use PhpCsFixer\FixerDefinition\CodeSample;
  79164. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79165. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79166. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  79167. use PhpCsFixer\Tokenizer\CT;
  79168. use PhpCsFixer\Tokenizer\Token;
  79169. use PhpCsFixer\Tokenizer\Tokens;
  79170. final class PhpUnitMockShortWillReturnFixer extends AbstractPhpUnitFixer
  79171. {
  79172. private const RETURN_METHODS_MAP = [
  79173. 'returnargument' => 'willReturnArgument',
  79174. 'returncallback' => 'willReturnCallback',
  79175. 'returnself' => 'willReturnSelf',
  79176. 'returnvalue' => 'willReturn',
  79177. 'returnvaluemap' => 'willReturnMap',
  79178. ];
  79179. public function getDefinition(): FixerDefinitionInterface
  79180. {
  79181. return new FixerDefinition(
  79182. 'Usage of PHPUnit\'s mock e.g. `->will($this->returnValue(..))` must be replaced by its shorter equivalent such as `->willReturn(...)`.',
  79183. [
  79184. new CodeSample('<?php
  79185. final class MyTest extends \PHPUnit_Framework_TestCase
  79186. {
  79187. public function testSomeTest()
  79188. {
  79189. $someMock = $this->createMock(Some::class);
  79190. $someMock->method("some")->will($this->returnSelf());
  79191. $someMock->method("some")->will($this->returnValue("example"));
  79192. $someMock->method("some")->will($this->returnArgument(2));
  79193. $someMock->method("some")->will($this->returnCallback("str_rot13"));
  79194. $someMock->method("some")->will($this->returnValueMap(["a","b","c"]));
  79195. }
  79196. }
  79197. '),
  79198. ],
  79199. null,
  79200. 'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
  79201. );
  79202. }
  79203. public function isRisky(): bool
  79204. {
  79205. return true;
  79206. }
  79207. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  79208. {
  79209. $functionsAnalyzer = new FunctionsAnalyzer();
  79210. for ($index = $startIndex; $index < $endIndex; ++$index) {
  79211. if (!$tokens[$index]->isObjectOperator()) {
  79212. continue;
  79213. }
  79214. $functionToReplaceIndex = $tokens->getNextMeaningfulToken($index);
  79215. if (!$tokens[$functionToReplaceIndex]->equals([T_STRING, 'will'], false)) {
  79216. continue;
  79217. }
  79218. $functionToReplaceOpeningBraceIndex = $tokens->getNextMeaningfulToken($functionToReplaceIndex);
  79219. if (!$tokens[$functionToReplaceOpeningBraceIndex]->equals('(')) {
  79220. continue;
  79221. }
  79222. $classReferenceIndex = $tokens->getNextMeaningfulToken($functionToReplaceOpeningBraceIndex);
  79223. $objectOperatorIndex = $tokens->getNextMeaningfulToken($classReferenceIndex);
  79224. $functionToRemoveIndex = $tokens->getNextMeaningfulToken($objectOperatorIndex);
  79225. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $functionToRemoveIndex)) {
  79226. continue;
  79227. }
  79228. if (!\array_key_exists(strtolower($tokens[$functionToRemoveIndex]->getContent()), self::RETURN_METHODS_MAP)) {
  79229. continue;
  79230. }
  79231. $openingBraceIndex = $tokens->getNextMeaningfulToken($functionToRemoveIndex);
  79232. if ($tokens[$tokens->getNextMeaningfulToken($openingBraceIndex)]->isGivenKind(CT::T_FIRST_CLASS_CALLABLE)) {
  79233. continue;
  79234. }
  79235. $closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingBraceIndex);
  79236. $tokens[$functionToReplaceIndex] = new Token([T_STRING, self::RETURN_METHODS_MAP[strtolower($tokens[$functionToRemoveIndex]->getContent())]]);
  79237. $tokens->clearTokenAndMergeSurroundingWhitespace($classReferenceIndex);
  79238. $tokens->clearTokenAndMergeSurroundingWhitespace($objectOperatorIndex);
  79239. $tokens->clearTokenAndMergeSurroundingWhitespace($functionToRemoveIndex);
  79240. $tokens->clearTokenAndMergeSurroundingWhitespace($openingBraceIndex);
  79241. $tokens->clearTokenAndMergeSurroundingWhitespace($closingBraceIndex);
  79242. $commaAfterClosingBraceIndex = $tokens->getNextMeaningfulToken($closingBraceIndex);
  79243. if ($tokens[$commaAfterClosingBraceIndex]->equals(',')) {
  79244. $tokens->clearTokenAndMergeSurroundingWhitespace($commaAfterClosingBraceIndex);
  79245. }
  79246. }
  79247. }
  79248. }
  79249. <?php
  79250. declare(strict_types=1);
  79251. namespace PhpCsFixer\Fixer\PhpUnit;
  79252. use PhpCsFixer\DocBlock\DocBlock;
  79253. use PhpCsFixer\DocBlock\Line;
  79254. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  79255. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  79256. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  79257. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  79258. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  79259. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  79260. use PhpCsFixer\FixerDefinition\CodeSample;
  79261. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79262. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79263. use PhpCsFixer\FixerDefinition\VersionSpecification;
  79264. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  79265. use PhpCsFixer\Preg;
  79266. use PhpCsFixer\Tokenizer\Token;
  79267. use PhpCsFixer\Tokenizer\Tokens;
  79268. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  79269. use PhpCsFixer\Utils;
  79270. /**
  79271. @phpstan-type
  79272. @phpstan-type
  79273. @implements
  79274. */
  79275. final class PhpUnitMethodCasingFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
  79276. {
  79277. /**
  79278. @use */
  79279. use ConfigurableFixerTrait;
  79280. public const CAMEL_CASE = 'camel_case';
  79281. public const SNAKE_CASE = 'snake_case';
  79282. public function getDefinition(): FixerDefinitionInterface
  79283. {
  79284. return new FixerDefinition(
  79285. 'Enforce camel (or snake) case for PHPUnit test methods, following configuration.',
  79286. [
  79287. new CodeSample(
  79288. '<?php
  79289. class MyTest extends \PhpUnit\FrameWork\TestCase
  79290. {
  79291. public function test_my_code() {}
  79292. }
  79293. '
  79294. ),
  79295. new CodeSample(
  79296. '<?php
  79297. class MyTest extends \PhpUnit\FrameWork\TestCase
  79298. {
  79299. public function testMyCode() {}
  79300. }
  79301. ',
  79302. ['case' => self::SNAKE_CASE]
  79303. ),
  79304. new VersionSpecificCodeSample(
  79305. '<?php
  79306. use \PHPUnit\Framework\Attributes\Test;
  79307. class MyTest extends \PhpUnit\FrameWork\TestCase
  79308. {
  79309. #[PHPUnit\Framework\Attributes\Test]
  79310. public function test_my_code() {}
  79311. }
  79312. ',
  79313. new VersionSpecification(8_00_00),
  79314. ),
  79315. new VersionSpecificCodeSample(
  79316. '<?php
  79317. use \PHPUnit\Framework\Attributes\Test;
  79318. class MyTest extends \PhpUnit\FrameWork\TestCase
  79319. {
  79320. #[PHPUnit\Framework\Attributes\Test]
  79321. public function testMyCode() {}
  79322. }
  79323. ',
  79324. new VersionSpecification(8_00_00),
  79325. ['case' => self::SNAKE_CASE]
  79326. ),
  79327. ]
  79328. );
  79329. }
  79330. public function getPriority(): int
  79331. {
  79332. return 0;
  79333. }
  79334. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  79335. {
  79336. return new FixerConfigurationResolver([
  79337. (new FixerOptionBuilder('case', 'Apply camel or snake case to test methods.'))
  79338. ->setAllowedValues([self::CAMEL_CASE, self::SNAKE_CASE])
  79339. ->setDefault(self::CAMEL_CASE)
  79340. ->getOption(),
  79341. ]);
  79342. }
  79343. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  79344. {
  79345. for ($index = $endIndex - 1; $index > $startIndex; --$index) {
  79346. if (!$this->isTestMethod($tokens, $index)) {
  79347. continue;
  79348. }
  79349. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  79350. $functionName = $tokens[$functionNameIndex]->getContent();
  79351. $newFunctionName = $this->updateMethodCasing($functionName);
  79352. if ($newFunctionName !== $functionName) {
  79353. $tokens[$functionNameIndex] = new Token([T_STRING, $newFunctionName]);
  79354. }
  79355. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  79356. if ($this->isPHPDoc($tokens, $docBlockIndex)) {
  79357. $this->updateDocBlock($tokens, $docBlockIndex);
  79358. }
  79359. }
  79360. }
  79361. private function updateMethodCasing(string $functionName): string
  79362. {
  79363. $parts = explode('::', $functionName);
  79364. $functionNamePart = array_pop($parts);
  79365. if (self::CAMEL_CASE === $this->configuration['case']) {
  79366. $newFunctionNamePart = $functionNamePart;
  79367. $newFunctionNamePart = ucwords($newFunctionNamePart, '_');
  79368. $newFunctionNamePart = str_replace('_', '', $newFunctionNamePart);
  79369. $newFunctionNamePart = lcfirst($newFunctionNamePart);
  79370. } else {
  79371. $newFunctionNamePart = Utils::camelCaseToUnderscore($functionNamePart);
  79372. }
  79373. $parts[] = $newFunctionNamePart;
  79374. return implode('::', $parts);
  79375. }
  79376. private function isTestMethod(Tokens $tokens, int $index): bool
  79377. {
  79378. if (!$this->isMethod($tokens, $index)) {
  79379. return false;
  79380. }
  79381. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  79382. $functionName = $tokens[$functionNameIndex]->getContent();
  79383. if (str_starts_with($functionName, 'test')) {
  79384. return true;
  79385. }
  79386. if ($this->isTestAttributePresent($tokens, $index)) {
  79387. return true;
  79388. }
  79389. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  79390. return
  79391. $this->isPHPDoc($tokens, $docBlockIndex)
  79392. && str_contains($tokens[$docBlockIndex]->getContent(), '@test');
  79393. }
  79394. private function isMethod(Tokens $tokens, int $index): bool
  79395. {
  79396. $tokensAnalyzer = new TokensAnalyzer($tokens);
  79397. return $tokens[$index]->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index);
  79398. }
  79399. private function updateDocBlock(Tokens $tokens, int $docBlockIndex): void
  79400. {
  79401. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  79402. $lines = $doc->getLines();
  79403. $docBlockNeedsUpdate = false;
  79404. for ($inc = 0; $inc < \count($lines); ++$inc) {
  79405. $lineContent = $lines[$inc]->getContent();
  79406. if (!str_contains($lineContent, '@depends')) {
  79407. continue;
  79408. }
  79409. $newLineContent = Preg::replaceCallback('/(@depends\s+)(.+)(\b)/', fn (array $matches): string => \sprintf(
  79410. '%s%s%s',
  79411. $matches[1],
  79412. $this->updateMethodCasing($matches[2]),
  79413. $matches[3]
  79414. ), $lineContent);
  79415. if ($newLineContent !== $lineContent) {
  79416. $lines[$inc] = new Line($newLineContent);
  79417. $docBlockNeedsUpdate = true;
  79418. }
  79419. }
  79420. if ($docBlockNeedsUpdate) {
  79421. $lines = implode('', $lines);
  79422. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  79423. }
  79424. }
  79425. }
  79426. <?php
  79427. declare(strict_types=1);
  79428. namespace PhpCsFixer\Fixer\PhpUnit;
  79429. use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
  79430. use PhpCsFixer\FixerDefinition\CodeSample;
  79431. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79432. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79433. use PhpCsFixer\Tokenizer\Token;
  79434. use PhpCsFixer\Tokenizer\Tokens;
  79435. final class PhpUnitAssertNewNamesFixer extends AbstractPhpUnitFixer
  79436. {
  79437. public function isRisky(): bool
  79438. {
  79439. return true;
  79440. }
  79441. public function getDefinition(): FixerDefinitionInterface
  79442. {
  79443. return new FixerDefinition(
  79444. 'Rename deprecated PHPUnit assertions like `assertFileNotExists` to new methods like `assertFileDoesNotExist`.',
  79445. [
  79446. new CodeSample(
  79447. '<?php
  79448. final class MyTest extends \PHPUnit_Framework_TestCase
  79449. {
  79450. public function testSomeTest()
  79451. {
  79452. $this->assertFileNotExists("test.php");
  79453. $this->assertNotIsWritable("path.php");
  79454. }
  79455. }
  79456. '
  79457. ),
  79458. ],
  79459. null,
  79460. 'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
  79461. );
  79462. }
  79463. public function getPriority(): int
  79464. {
  79465. return -10;
  79466. }
  79467. protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
  79468. {
  79469. foreach ($this->getPreviousAssertCall($tokens, $startIndex, $endIndex) as $assertCall) {
  79470. $this->fixAssertNewNames($tokens, $assertCall);
  79471. }
  79472. }
  79473. private function fixAssertNewNames(Tokens $tokens, array $assertCall): void
  79474. {
  79475. $replacements = [
  79476. 'assertnotisreadable' => 'assertIsNotReadable',
  79477. 'assertnotiswritable' => 'assertIsNotWritable',
  79478. 'assertdirectorynotexists' => 'assertDirectoryDoesNotExist',
  79479. 'assertfilenotexists' => 'assertFileDoesNotExist',
  79480. 'assertdirectorynotisreadable' => 'assertDirectoryIsNotReadable',
  79481. 'assertdirectorynotiswritable' => 'assertDirectoryIsNotWriteable',
  79482. 'assertfilenotisreadable' => 'assertFileIsNotReadable',
  79483. 'assertfilenotiswritable' => 'assertFileIsNotWriteable',
  79484. 'assertregexp' => 'assertMatchesRegularExpression',
  79485. 'assertnotregexp' => 'assertDoesNotMatchRegularExpression',
  79486. ];
  79487. $replacement = $replacements[$assertCall['loweredName']] ?? null;
  79488. if (null === $replacement) {
  79489. return;
  79490. }
  79491. $tokens[$assertCall['index']] = new Token([
  79492. T_STRING,
  79493. $replacement,
  79494. ]);
  79495. }
  79496. }
  79497. <?php
  79498. declare(strict_types=1);
  79499. namespace PhpCsFixer\Fixer;
  79500. use PhpCsFixer\AbstractFixer;
  79501. use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
  79502. use PhpCsFixer\Tokenizer\Analyzer\RangeAnalyzer;
  79503. use PhpCsFixer\Tokenizer\CT;
  79504. use PhpCsFixer\Tokenizer\Token;
  79505. use PhpCsFixer\Tokenizer\Tokens;
  79506. abstract class AbstractShortOperatorFixer extends AbstractFixer
  79507. {
  79508. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  79509. {
  79510. $alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
  79511. for ($index = \count($tokens) - 1; $index > 3; --$index) {
  79512. if (!$this->isOperatorTokenCandidate($tokens, $index)) {
  79513. continue;
  79514. }
  79515. $beforeRange = $this->getBeforeOperatorRange($tokens, $index);
  79516. $equalsIndex = $tokens->getPrevMeaningfulToken($beforeRange['start']);
  79517. if (!$tokens[$equalsIndex]->equals('=')) {
  79518. continue;
  79519. }
  79520. $assignRange = $this->getBeforeOperatorRange($tokens, $equalsIndex);
  79521. $beforeAssignmentIndex = $tokens->getPrevMeaningfulToken($assignRange['start']);
  79522. if ($tokens[$beforeAssignmentIndex]->equals(':')) {
  79523. if (!$this->belongsToSwitchOrAlternativeSyntax($alternativeSyntaxAnalyzer, $tokens, $beforeAssignmentIndex)) {
  79524. continue;
  79525. }
  79526. } elseif (!$tokens[$beforeAssignmentIndex]->equalsAny([';', '{', '}', '(', ')', ',', [T_OPEN_TAG], [T_RETURN]])) {
  79527. continue;
  79528. }
  79529. if (RangeAnalyzer::rangeEqualsRange($tokens, $assignRange, $beforeRange)) {
  79530. $this->shortenOperation($tokens, $equalsIndex, $index, $assignRange, $beforeRange);
  79531. continue;
  79532. }
  79533. if (!$this->isOperatorCommutative($tokens[$index])) {
  79534. continue;
  79535. }
  79536. $afterRange = $this->getAfterOperatorRange($tokens, $index);
  79537. if (!RangeAnalyzer::rangeEqualsRange($tokens, $assignRange, $afterRange)) {
  79538. continue;
  79539. }
  79540. $this->shortenOperation($tokens, $equalsIndex, $index, $assignRange, $afterRange);
  79541. }
  79542. }
  79543. abstract protected function getReplacementToken(Token $token): Token;
  79544. abstract protected function isOperatorTokenCandidate(Tokens $tokens, int $index): bool;
  79545. private function shortenOperation(
  79546. Tokens $tokens,
  79547. int $equalsIndex,
  79548. int $operatorIndex,
  79549. array $assignRange,
  79550. array $operatorRange
  79551. ): void {
  79552. $tokens[$equalsIndex] = $this->getReplacementToken($tokens[$operatorIndex]);
  79553. $tokens->clearTokenAndMergeSurroundingWhitespace($operatorIndex);
  79554. $this->clearMeaningfulFromRange($tokens, $operatorRange);
  79555. foreach ([$equalsIndex, $assignRange['end']] as $i) {
  79556. $i = $tokens->getNonEmptySibling($i, 1);
  79557. if ($tokens[$i]->isWhitespace(" \t")) {
  79558. $tokens[$i] = new Token([T_WHITESPACE, ' ']);
  79559. } elseif (!$tokens[$i]->isWhitespace()) {
  79560. $tokens->insertAt($i, new Token([T_WHITESPACE, ' ']));
  79561. }
  79562. }
  79563. }
  79564. private function getAfterOperatorRange(Tokens $tokens, int $index): array
  79565. {
  79566. $index = $tokens->getNextMeaningfulToken($index);
  79567. $range = ['start' => $index];
  79568. while (true) {
  79569. $nextIndex = $tokens->getNextMeaningfulToken($index);
  79570. if (null === $nextIndex || $tokens[$nextIndex]->equalsAny([';', ',', [T_CLOSE_TAG]])) {
  79571. break;
  79572. }
  79573. $blockType = Tokens::detectBlockType($tokens[$nextIndex]);
  79574. if (null === $blockType) {
  79575. $index = $nextIndex;
  79576. continue;
  79577. }
  79578. if (false === $blockType['isStart']) {
  79579. break;
  79580. }
  79581. $index = $tokens->findBlockEnd($blockType['type'], $nextIndex);
  79582. }
  79583. $range['end'] = $index;
  79584. return $range;
  79585. }
  79586. private function getBeforeOperatorRange(Tokens $tokens, int $index): array
  79587. {
  79588. static $blockOpenTypes;
  79589. if (null === $blockOpenTypes) {
  79590. $blockOpenTypes = [','];
  79591. foreach (Tokens::getBlockEdgeDefinitions() as $definition) {
  79592. $blockOpenTypes[] = $definition['start'];
  79593. }
  79594. }
  79595. $controlStructureWithoutBracesTypes = [T_IF, T_ELSE, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE];
  79596. $previousIndex = $tokens->getPrevMeaningfulToken($index);
  79597. $previousToken = $tokens[$previousIndex];
  79598. if ($tokens[$previousIndex]->equalsAny($blockOpenTypes)) {
  79599. return ['start' => $index, 'end' => $index];
  79600. }
  79601. $range = ['end' => $previousIndex];
  79602. $index = $previousIndex;
  79603. while ($previousToken->equalsAny([
  79604. '$',
  79605. ']',
  79606. ')',
  79607. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  79608. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  79609. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  79610. [T_NS_SEPARATOR],
  79611. [T_STRING],
  79612. [T_VARIABLE],
  79613. ])) {
  79614. $blockType = Tokens::detectBlockType($previousToken);
  79615. if (null !== $blockType) {
  79616. $blockStart = $tokens->findBlockStart($blockType['type'], $previousIndex);
  79617. if ($tokens[$previousIndex]->equals(')') && $tokens[$tokens->getPrevMeaningfulToken($blockStart)]->isGivenKind($controlStructureWithoutBracesTypes)) {
  79618. break;
  79619. }
  79620. $previousIndex = $blockStart;
  79621. }
  79622. $index = $previousIndex;
  79623. $previousIndex = $tokens->getPrevMeaningfulToken($previousIndex);
  79624. $previousToken = $tokens[$previousIndex];
  79625. }
  79626. if ($previousToken->isGivenKind(T_OBJECT_OPERATOR)) {
  79627. $index = $this->getBeforeOperatorRange($tokens, $previousIndex)['start'];
  79628. } elseif ($previousToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  79629. $index = $this->getBeforeOperatorRange($tokens, $tokens->getPrevMeaningfulToken($previousIndex))['start'];
  79630. }
  79631. $range['start'] = $index;
  79632. return $range;
  79633. }
  79634. private function clearMeaningfulFromRange(Tokens $tokens, array $range): void
  79635. {
  79636. for ($i = $range['end']; $i >= $range['start']; $i = $tokens->getPrevMeaningfulToken($i)) {
  79637. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  79638. }
  79639. }
  79640. private function isOperatorCommutative(Token $operatorToken): bool
  79641. {
  79642. static $commutativeKinds = ['*', '|', '&', '^'];
  79643. static $nonCommutativeKinds = ['-', '/', '.', '%', '+'];
  79644. if ($operatorToken->isGivenKind(T_COALESCE)) {
  79645. return false;
  79646. }
  79647. if ($operatorToken->equalsAny($commutativeKinds)) {
  79648. return true;
  79649. }
  79650. if ($operatorToken->equalsAny($nonCommutativeKinds)) {
  79651. return false;
  79652. }
  79653. throw new \InvalidArgumentException(\sprintf('Not supported operator "%s".', $operatorToken->toJson()));
  79654. }
  79655. private function belongsToSwitchOrAlternativeSyntax(AlternativeSyntaxAnalyzer $alternativeSyntaxAnalyzer, Tokens $tokens, int $index): bool
  79656. {
  79657. $candidate = $index;
  79658. $index = $tokens->getPrevMeaningfulToken($candidate);
  79659. if ($tokens[$index]->isGivenKind(T_DEFAULT)) {
  79660. return true;
  79661. }
  79662. $index = $tokens->getPrevMeaningfulToken($index);
  79663. if ($tokens[$index]->isGivenKind(T_CASE)) {
  79664. return true;
  79665. }
  79666. return $alternativeSyntaxAnalyzer->belongsToAlternativeSyntax($tokens, $candidate);
  79667. }
  79668. }
  79669. <?php
  79670. declare(strict_types=1);
  79671. namespace PhpCsFixer\Fixer;
  79672. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  79673. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  79674. /**
  79675. @template
  79676. @template
  79677. */
  79678. interface ConfigurableFixerInterface extends FixerInterface
  79679. {
  79680. public function configure(array $configuration): void;
  79681. public function getConfigurationDefinition(): FixerConfigurationResolverInterface;
  79682. }
  79683. <?php
  79684. declare(strict_types=1);
  79685. namespace PhpCsFixer\Fixer\Whitespace;
  79686. use PhpCsFixer\AbstractProxyFixer;
  79687. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  79688. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79689. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79690. final class CompactNullableTypehintFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  79691. {
  79692. private CompactNullableTypeDeclarationFixer $compactNullableTypeDeclarationFixer;
  79693. public function __construct()
  79694. {
  79695. $this->compactNullableTypeDeclarationFixer = new CompactNullableTypeDeclarationFixer();
  79696. parent::__construct();
  79697. }
  79698. public function getDefinition(): FixerDefinitionInterface
  79699. {
  79700. $fixerDefinition = $this->compactNullableTypeDeclarationFixer->getDefinition();
  79701. return new FixerDefinition(
  79702. 'Remove extra spaces in a nullable typehint.',
  79703. $fixerDefinition->getCodeSamples(),
  79704. $fixerDefinition->getDescription(),
  79705. $fixerDefinition->getRiskyDescription(),
  79706. );
  79707. }
  79708. public function getSuccessorsNames(): array
  79709. {
  79710. return [
  79711. $this->compactNullableTypeDeclarationFixer->getName(),
  79712. ];
  79713. }
  79714. protected function createProxyFixers(): array
  79715. {
  79716. return [
  79717. $this->compactNullableTypeDeclarationFixer,
  79718. ];
  79719. }
  79720. }
  79721. <?php
  79722. declare(strict_types=1);
  79723. namespace PhpCsFixer\Fixer\Whitespace;
  79724. use PhpCsFixer\AbstractFixer;
  79725. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  79726. use PhpCsFixer\FixerDefinition\CodeSample;
  79727. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79728. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79729. use PhpCsFixer\Preg;
  79730. use PhpCsFixer\Tokenizer\Token;
  79731. use PhpCsFixer\Tokenizer\Tokens;
  79732. final class LineEndingFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  79733. {
  79734. public function isCandidate(Tokens $tokens): bool
  79735. {
  79736. return true;
  79737. }
  79738. public function getDefinition(): FixerDefinitionInterface
  79739. {
  79740. return new FixerDefinition(
  79741. 'All PHP files must use same line ending.',
  79742. [
  79743. new CodeSample(
  79744. "<?php \$b = \" \$a \r\n 123\"; \$a = <<<TEST\r\nAAAAA \r\n |\r\nTEST;\n"
  79745. ),
  79746. ]
  79747. );
  79748. }
  79749. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  79750. {
  79751. $ending = $this->whitespacesConfig->getLineEnding();
  79752. for ($index = 0, $count = \count($tokens); $index < $count; ++$index) {
  79753. $token = $tokens[$index];
  79754. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  79755. if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_END_HEREDOC)) {
  79756. $tokens[$index] = new Token([
  79757. $token->getId(),
  79758. Preg::replace(
  79759. '#\R#',
  79760. $ending,
  79761. $token->getContent()
  79762. ),
  79763. ]);
  79764. }
  79765. continue;
  79766. }
  79767. if ($token->isGivenKind([T_CLOSE_TAG, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG, T_START_HEREDOC, T_WHITESPACE])) {
  79768. $tokens[$index] = new Token([
  79769. $token->getId(),
  79770. Preg::replace(
  79771. '#\R#',
  79772. $ending,
  79773. $token->getContent()
  79774. ),
  79775. ]);
  79776. }
  79777. }
  79778. }
  79779. }
  79780. <?php
  79781. declare(strict_types=1);
  79782. namespace PhpCsFixer\Fixer\Whitespace;
  79783. use PhpCsFixer\AbstractFixer;
  79784. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  79785. use PhpCsFixer\FixerDefinition\CodeSample;
  79786. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79787. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79788. use PhpCsFixer\Tokenizer\Tokens;
  79789. final class SingleBlankLineAtEofFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  79790. {
  79791. public function getDefinition(): FixerDefinitionInterface
  79792. {
  79793. return new FixerDefinition(
  79794. 'A PHP file without end tag must always end with a single empty line feed.',
  79795. [
  79796. new CodeSample("<?php\n\$a = 1;"),
  79797. new CodeSample("<?php\n\$a = 1;\n\n"),
  79798. ]
  79799. );
  79800. }
  79801. public function getPriority(): int
  79802. {
  79803. return -100;
  79804. }
  79805. public function isCandidate(Tokens $tokens): bool
  79806. {
  79807. return true;
  79808. }
  79809. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  79810. {
  79811. $count = $tokens->count();
  79812. if ($count > 0 && !$tokens[$count - 1]->isGivenKind([T_INLINE_HTML, T_CLOSE_TAG, T_OPEN_TAG])) {
  79813. $tokens->ensureWhitespaceAtIndex($count - 1, 1, $this->whitespacesConfig->getLineEnding());
  79814. }
  79815. }
  79816. }
  79817. <?php
  79818. declare(strict_types=1);
  79819. namespace PhpCsFixer\Fixer\Whitespace;
  79820. use PhpCsFixer\AbstractFixer;
  79821. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  79822. use PhpCsFixer\FixerDefinition\CodeSample;
  79823. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79824. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79825. use PhpCsFixer\Preg;
  79826. use PhpCsFixer\Tokenizer\Token;
  79827. use PhpCsFixer\Tokenizer\Tokens;
  79828. final class IndentationTypeFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  79829. {
  79830. private string $indent;
  79831. public function getDefinition(): FixerDefinitionInterface
  79832. {
  79833. return new FixerDefinition(
  79834. 'Code MUST use configured indentation type.',
  79835. [
  79836. new CodeSample("<?php\n\nif (true) {\n\techo 'Hello!';\n}\n"),
  79837. ]
  79838. );
  79839. }
  79840. public function getPriority(): int
  79841. {
  79842. return 50;
  79843. }
  79844. public function isCandidate(Tokens $tokens): bool
  79845. {
  79846. return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT, T_WHITESPACE]);
  79847. }
  79848. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  79849. {
  79850. $this->indent = $this->whitespacesConfig->getIndent();
  79851. foreach ($tokens as $index => $token) {
  79852. if ($token->isComment()) {
  79853. $tokens[$index] = $this->fixIndentInComment($tokens, $index);
  79854. continue;
  79855. }
  79856. if ($token->isWhitespace()) {
  79857. $tokens[$index] = $this->fixIndentToken($tokens, $index);
  79858. continue;
  79859. }
  79860. }
  79861. }
  79862. private function fixIndentInComment(Tokens $tokens, int $index): Token
  79863. {
  79864. $content = Preg::replace('/^(?:(?<! ) {1,3})?\t/m', '\1 ', $tokens[$index]->getContent(), -1, $count);
  79865. while (0 !== $count) {
  79866. $content = Preg::replace('/^(\ +)?\t/m', '\1 ', $content, -1, $count);
  79867. }
  79868. $indent = $this->indent;
  79869. $content = Preg::replaceCallback('/^(?: )+/m', fn (array $matches): string => $this->getExpectedIndent($matches[0], $indent), $content);
  79870. return new Token([$tokens[$index]->getId(), $content]);
  79871. }
  79872. private function fixIndentToken(Tokens $tokens, int $index): Token
  79873. {
  79874. $content = $tokens[$index]->getContent();
  79875. $previousTokenHasTrailingLinebreak = false;
  79876. if (str_contains($tokens[$index - 1]->getContent(), "\n")) {
  79877. $content = "\n".$content;
  79878. $previousTokenHasTrailingLinebreak = true;
  79879. }
  79880. $indent = $this->indent;
  79881. $newContent = Preg::replaceCallback(
  79882. '/(\R)(\h+)/',
  79883. function (array $matches) use ($indent): string {
  79884. $content = Preg::replace('/(?:(?<! ) {1,3})?\t/', ' ', $matches[2]);
  79885. return $matches[1].$this->getExpectedIndent($content, $indent);
  79886. },
  79887. $content
  79888. );
  79889. if ($previousTokenHasTrailingLinebreak) {
  79890. $newContent = substr($newContent, 1);
  79891. }
  79892. return new Token([T_WHITESPACE, $newContent]);
  79893. }
  79894. private function getExpectedIndent(string $content, string $indent): string
  79895. {
  79896. if ("\t" === $indent) {
  79897. $content = str_replace(' ', $indent, $content);
  79898. }
  79899. return $content;
  79900. }
  79901. }
  79902. <?php
  79903. declare(strict_types=1);
  79904. namespace PhpCsFixer\Fixer\Whitespace;
  79905. use PhpCsFixer\AbstractFixer;
  79906. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  79907. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  79908. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  79909. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  79910. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  79911. use PhpCsFixer\FixerDefinition\CodeSample;
  79912. use PhpCsFixer\FixerDefinition\FixerDefinition;
  79913. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  79914. use PhpCsFixer\Tokenizer\CT;
  79915. use PhpCsFixer\Tokenizer\Token;
  79916. use PhpCsFixer\Tokenizer\Tokens;
  79917. /**
  79918. @phpstan-type
  79919. @phpstan-type
  79920. @implements
  79921. */
  79922. final class SpacesInsideParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
  79923. {
  79924. /**
  79925. @use */
  79926. use ConfigurableFixerTrait;
  79927. public function getDefinition(): FixerDefinitionInterface
  79928. {
  79929. return new FixerDefinition(
  79930. 'Parentheses must be declared using the configured whitespace.',
  79931. [
  79932. new CodeSample("<?php\nif ( \$a ) {\n foo( );\n}\n"),
  79933. new CodeSample(
  79934. "<?php
  79935. function foo( \$bar, \$baz )
  79936. {
  79937. }\n",
  79938. ['space' => 'none']
  79939. ),
  79940. new CodeSample(
  79941. "<?php\nif (\$a) {\n foo( );\n}\n",
  79942. ['space' => 'single']
  79943. ),
  79944. new CodeSample(
  79945. "<?php
  79946. function foo(\$bar, \$baz)
  79947. {
  79948. }\n",
  79949. ['space' => 'single']
  79950. ),
  79951. ],
  79952. 'By default there are not any additional spaces inside parentheses, however with `space=single` configuration option whitespace inside parentheses will be unified to single space.'
  79953. );
  79954. }
  79955. public function getPriority(): int
  79956. {
  79957. return 3;
  79958. }
  79959. public function isCandidate(Tokens $tokens): bool
  79960. {
  79961. return $tokens->isAnyTokenKindsFound(['(', CT::T_BRACE_CLASS_INSTANTIATION_OPEN]);
  79962. }
  79963. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  79964. {
  79965. if ('none' === $this->configuration['space']) {
  79966. foreach ($tokens as $index => $token) {
  79967. if (!$token->equalsAny(['(', [CT::T_BRACE_CLASS_INSTANTIATION_OPEN]])) {
  79968. continue;
  79969. }
  79970. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  79971. if (null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_ARRAY)) {
  79972. continue;
  79973. }
  79974. $blockType = Tokens::detectBlockType($token);
  79975. $endIndex = $tokens->findBlockEnd($blockType['type'], $index);
  79976. if (!$tokens[$tokens->getNextNonWhitespace($index)]->isComment()) {
  79977. $this->removeSpaceAroundToken($tokens, $index + 1);
  79978. }
  79979. if (!$tokens[$tokens->getPrevMeaningfulToken($endIndex)]->equals(',')) {
  79980. $this->removeSpaceAroundToken($tokens, $endIndex - 1);
  79981. }
  79982. }
  79983. }
  79984. if ('single' === $this->configuration['space']) {
  79985. foreach ($tokens as $index => $token) {
  79986. if (!$token->equalsAny(['(', [CT::T_BRACE_CLASS_INSTANTIATION_OPEN]])) {
  79987. continue;
  79988. }
  79989. $blockType = Tokens::detectBlockType($token);
  79990. $endParenthesisIndex = $tokens->findBlockEnd($blockType['type'], $index);
  79991. $blockContent = $this->getBlockContent($index, $endParenthesisIndex, $tokens);
  79992. if (1 === \count($blockContent) && \in_array(' ', $blockContent, true)) {
  79993. $this->removeSpaceAroundToken($tokens, $index + 1);
  79994. continue;
  79995. }
  79996. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index);
  79997. if (')' === $tokens[$nextMeaningfulTokenIndex]->getContent()) {
  79998. continue;
  79999. }
  80000. $afterParenthesisIndex = $tokens->getNextNonWhitespace($endParenthesisIndex);
  80001. $afterParenthesisToken = $tokens[$afterParenthesisIndex];
  80002. if ($afterParenthesisToken->isGivenKind(CT::T_USE_LAMBDA)) {
  80003. $useStartParenthesisIndex = $tokens->getNextTokenOfKind($afterParenthesisIndex, ['(']);
  80004. $useEndParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $useStartParenthesisIndex);
  80005. $this->fixParenthesisInnerEdge($tokens, $useStartParenthesisIndex, $useEndParenthesisIndex);
  80006. }
  80007. $this->fixParenthesisInnerEdge($tokens, $index, $endParenthesisIndex);
  80008. }
  80009. }
  80010. }
  80011. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  80012. {
  80013. return new FixerConfigurationResolver([
  80014. (new FixerOptionBuilder('space', 'Whether to have `single` or `none` space inside parentheses.'))
  80015. ->setAllowedValues(['none', 'single'])
  80016. ->setDefault('none')
  80017. ->getOption(),
  80018. ]);
  80019. }
  80020. private function removeSpaceAroundToken(Tokens $tokens, int $index): void
  80021. {
  80022. $token = $tokens[$index];
  80023. if ($token->isWhitespace() && !str_contains($token->getContent(), "\n")) {
  80024. $tokens->clearAt($index);
  80025. }
  80026. }
  80027. private function fixParenthesisInnerEdge(Tokens $tokens, int $start, int $end): void
  80028. {
  80029. if ($tokens[$end - 1]->isWhitespace()) {
  80030. $content = $tokens[$end - 1]->getContent();
  80031. if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($end - 1)]->isComment()) {
  80032. $tokens[$end - 1] = new Token([T_WHITESPACE, ' ']);
  80033. }
  80034. } else {
  80035. $tokens->insertAt($end, new Token([T_WHITESPACE, ' ']));
  80036. }
  80037. if ($tokens[$start + 1]->isWhitespace()) {
  80038. $content = $tokens[$start + 1]->getContent();
  80039. if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($start + 1)]->isComment()) {
  80040. $tokens[$start + 1] = new Token([T_WHITESPACE, ' ']);
  80041. }
  80042. } else {
  80043. $tokens->insertAt($start + 1, new Token([T_WHITESPACE, ' ']));
  80044. }
  80045. }
  80046. private function getBlockContent(int $startIndex, int $endIndex, Tokens $tokens): array
  80047. {
  80048. $contents = [];
  80049. for ($i = ($startIndex + 1); $i < $endIndex; ++$i) {
  80050. $contents[] = $tokens[$i]->getContent();
  80051. }
  80052. return $contents;
  80053. }
  80054. }
  80055. <?php
  80056. declare(strict_types=1);
  80057. namespace PhpCsFixer\Fixer\Whitespace;
  80058. use PhpCsFixer\AbstractFixer;
  80059. use PhpCsFixer\Fixer\Indentation;
  80060. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  80061. use PhpCsFixer\FixerDefinition\CodeSample;
  80062. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80063. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80064. use PhpCsFixer\Preg;
  80065. use PhpCsFixer\Tokenizer\CT;
  80066. use PhpCsFixer\Tokenizer\Token;
  80067. use PhpCsFixer\Tokenizer\Tokens;
  80068. final class ArrayIndentationFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  80069. {
  80070. use Indentation;
  80071. public function getDefinition(): FixerDefinitionInterface
  80072. {
  80073. return new FixerDefinition(
  80074. 'Each element of an array must be indented exactly once.',
  80075. [
  80076. new CodeSample("<?php\n\$foo = [\n 'bar' => [\n 'baz' => true,\n ],\n];\n"),
  80077. ]
  80078. );
  80079. }
  80080. public function isCandidate(Tokens $tokens): bool
  80081. {
  80082. return $tokens->isAnyTokenKindsFound([T_ARRAY, T_LIST, CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN]);
  80083. }
  80084. public function getPriority(): int
  80085. {
  80086. return 29;
  80087. }
  80088. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80089. {
  80090. $lastIndent = '';
  80091. $scopes = [];
  80092. $previousLineInitialIndent = '';
  80093. $previousLineNewIndent = '';
  80094. foreach ($tokens as $index => $token) {
  80095. $currentScope = [] !== $scopes ? \count($scopes) - 1 : null;
  80096. if ($token->isComment()) {
  80097. continue;
  80098. }
  80099. if (
  80100. $token->isGivenKind([CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN])
  80101. || ($token->equals('(') && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind([T_ARRAY, T_LIST]))
  80102. ) {
  80103. $blockType = Tokens::detectBlockType($token);
  80104. $endIndex = $tokens->findBlockEnd($blockType['type'], $index);
  80105. $scopes[] = [
  80106. 'type' => 'array',
  80107. 'end_index' => $endIndex,
  80108. 'initial_indent' => $lastIndent,
  80109. ];
  80110. continue;
  80111. }
  80112. if ($this->isNewLineToken($tokens, $index)) {
  80113. $lastIndent = $this->extractIndent($this->computeNewLineContent($tokens, $index));
  80114. }
  80115. if (null === $currentScope) {
  80116. continue;
  80117. }
  80118. if ($token->isWhitespace()) {
  80119. if (!Preg::match('/\R/', $token->getContent())) {
  80120. continue;
  80121. }
  80122. if ('array' === $scopes[$currentScope]['type']) {
  80123. $indent = false;
  80124. for ($searchEndIndex = $index + 1; $searchEndIndex < $scopes[$currentScope]['end_index']; ++$searchEndIndex) {
  80125. $searchEndToken = $tokens[$searchEndIndex];
  80126. if (
  80127. (!$searchEndToken->isWhitespace() && !$searchEndToken->isComment())
  80128. || ($searchEndToken->isWhitespace() && Preg::match('/\R/', $searchEndToken->getContent()))
  80129. ) {
  80130. $indent = true;
  80131. break;
  80132. }
  80133. }
  80134. $content = Preg::replace(
  80135. '/(\R+)\h*$/',
  80136. '$1'.$scopes[$currentScope]['initial_indent'].($indent ? $this->whitespacesConfig->getIndent() : ''),
  80137. $token->getContent()
  80138. );
  80139. $previousLineInitialIndent = $this->extractIndent($token->getContent());
  80140. $previousLineNewIndent = $this->extractIndent($content);
  80141. } else {
  80142. $content = Preg::replace(
  80143. '/(\R)'.preg_quote($scopes[$currentScope]['initial_indent'], '/').'(\h*)$/',
  80144. '$1'.$scopes[$currentScope]['new_indent'].'$2',
  80145. $token->getContent()
  80146. );
  80147. }
  80148. $tokens[$index] = new Token([T_WHITESPACE, $content]);
  80149. $lastIndent = $this->extractIndent($content);
  80150. continue;
  80151. }
  80152. if ($index === $scopes[$currentScope]['end_index']) {
  80153. while ([] !== $scopes && $index === $scopes[$currentScope]['end_index']) {
  80154. array_pop($scopes);
  80155. --$currentScope;
  80156. }
  80157. continue;
  80158. }
  80159. if ($token->equals(',')) {
  80160. continue;
  80161. }
  80162. if ('expression' !== $scopes[$currentScope]['type']) {
  80163. $endIndex = $this->findExpressionEndIndex($tokens, $index, $scopes[$currentScope]['end_index']);
  80164. if ($endIndex === $index) {
  80165. continue;
  80166. }
  80167. $scopes[] = [
  80168. 'type' => 'expression',
  80169. 'end_index' => $endIndex,
  80170. 'initial_indent' => $previousLineInitialIndent,
  80171. 'new_indent' => $previousLineNewIndent,
  80172. ];
  80173. }
  80174. }
  80175. }
  80176. private function findExpressionEndIndex(Tokens $tokens, int $index, int $parentScopeEndIndex): int
  80177. {
  80178. $endIndex = null;
  80179. for ($searchEndIndex = $index + 1; $searchEndIndex < $parentScopeEndIndex; ++$searchEndIndex) {
  80180. $searchEndToken = $tokens[$searchEndIndex];
  80181. if ($searchEndToken->equalsAny(['(', '{'])
  80182. || $searchEndToken->isGivenKind([CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN])
  80183. ) {
  80184. $type = Tokens::detectBlockType($searchEndToken);
  80185. $searchEndIndex = $tokens->findBlockEnd(
  80186. $type['type'],
  80187. $searchEndIndex
  80188. );
  80189. continue;
  80190. }
  80191. if ($searchEndToken->equals(',')) {
  80192. $endIndex = $tokens->getPrevMeaningfulToken($searchEndIndex);
  80193. break;
  80194. }
  80195. }
  80196. return $endIndex ?? $tokens->getPrevMeaningfulToken($parentScopeEndIndex);
  80197. }
  80198. }
  80199. <?php
  80200. declare(strict_types=1);
  80201. namespace PhpCsFixer\Fixer\Whitespace;
  80202. use PhpCsFixer\AbstractFixer;
  80203. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  80204. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  80205. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  80206. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  80207. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  80208. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  80209. use PhpCsFixer\FixerDefinition\CodeSample;
  80210. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80211. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80212. use PhpCsFixer\Tokenizer\CT;
  80213. use PhpCsFixer\Tokenizer\Tokens;
  80214. /**
  80215. @phpstan-type
  80216. @phpstan-type
  80217. @implements
  80218. */
  80219. final class NoSpacesAroundOffsetFixer extends AbstractFixer implements ConfigurableFixerInterface
  80220. {
  80221. /**
  80222. @use */
  80223. use ConfigurableFixerTrait;
  80224. public function getDefinition(): FixerDefinitionInterface
  80225. {
  80226. return new FixerDefinition(
  80227. 'There MUST NOT be spaces around offset braces.',
  80228. [
  80229. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n"),
  80230. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n", ['positions' => ['inside']]),
  80231. new CodeSample("<?php\n\$sample = \$b [ 'a' ] [ 'b' ];\n", ['positions' => ['outside']]),
  80232. ]
  80233. );
  80234. }
  80235. public function isCandidate(Tokens $tokens): bool
  80236. {
  80237. return $tokens->isAnyTokenKindsFound(['[', CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]);
  80238. }
  80239. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80240. {
  80241. foreach ($tokens as $index => $token) {
  80242. if (!$token->equalsAny(['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]])) {
  80243. continue;
  80244. }
  80245. if (\in_array('inside', $this->configuration['positions'], true)) {
  80246. if ($token->equals('[')) {
  80247. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  80248. } else {
  80249. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE, $index);
  80250. }
  80251. if ($tokens[$index + 1]->isWhitespace(" \t")) {
  80252. $tokens->clearAt($index + 1);
  80253. }
  80254. if ($tokens[$endIndex - 1]->isWhitespace(" \t")) {
  80255. $tokens->clearAt($endIndex - 1);
  80256. }
  80257. }
  80258. if (\in_array('outside', $this->configuration['positions'], true)) {
  80259. $prevNonWhitespaceIndex = $tokens->getPrevNonWhitespace($index);
  80260. if ($tokens[$prevNonWhitespaceIndex]->isComment()) {
  80261. continue;
  80262. }
  80263. $tokens->removeLeadingWhitespace($index);
  80264. }
  80265. }
  80266. }
  80267. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  80268. {
  80269. $values = ['inside', 'outside'];
  80270. return new FixerConfigurationResolver([
  80271. (new FixerOptionBuilder('positions', 'Whether spacing should be fixed inside and/or outside the offset braces.'))
  80272. ->setAllowedTypes(['string[]'])
  80273. ->setAllowedValues([new AllowedValueSubset($values)])
  80274. ->setDefault($values)
  80275. ->getOption(),
  80276. ]);
  80277. }
  80278. }
  80279. <?php
  80280. declare(strict_types=1);
  80281. namespace PhpCsFixer\Fixer\Whitespace;
  80282. use PhpCsFixer\AbstractFixer;
  80283. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  80284. use PhpCsFixer\FixerDefinition\CodeSample;
  80285. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80286. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80287. use PhpCsFixer\Preg;
  80288. use PhpCsFixer\Tokenizer\Tokens;
  80289. final class NoWhitespaceInBlankLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  80290. {
  80291. public function getDefinition(): FixerDefinitionInterface
  80292. {
  80293. return new FixerDefinition(
  80294. 'Remove trailing whitespace at the end of blank lines.',
  80295. [new CodeSample("<?php\n \n\$a = 1;\n")]
  80296. );
  80297. }
  80298. public function getPriority(): int
  80299. {
  80300. return -99;
  80301. }
  80302. public function isCandidate(Tokens $tokens): bool
  80303. {
  80304. return true;
  80305. }
  80306. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80307. {
  80308. for ($i = 1, $count = \count($tokens); $i < $count; ++$i) {
  80309. if ($tokens[$i]->isWhitespace()) {
  80310. $this->fixWhitespaceToken($tokens, $i);
  80311. }
  80312. }
  80313. }
  80314. private function fixWhitespaceToken(Tokens $tokens, int $index): void
  80315. {
  80316. $content = $tokens[$index]->getContent();
  80317. $lines = Preg::split("/(\r\n|\n)/", $content);
  80318. $lineCount = \count($lines);
  80319. if (
  80320. $lineCount > 2
  80321. || ($lineCount > 0 && (!isset($tokens[$index + 1]) || $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)))
  80322. ) {
  80323. $lMax = isset($tokens[$index + 1]) ? $lineCount - 1 : $lineCount;
  80324. $lStart = 1;
  80325. if ($tokens[$index - 1]->isGivenKind(T_OPEN_TAG) && "\n" === substr($tokens[$index - 1]->getContent(), -1)) {
  80326. $lStart = 0;
  80327. }
  80328. for ($l = $lStart; $l < $lMax; ++$l) {
  80329. $lines[$l] = Preg::replace('/^\h+$/', '', $lines[$l]);
  80330. }
  80331. $content = implode($this->whitespacesConfig->getLineEnding(), $lines);
  80332. $tokens->ensureWhitespaceAtIndex($index, 0, $content);
  80333. }
  80334. }
  80335. }
  80336. <?php
  80337. declare(strict_types=1);
  80338. namespace PhpCsFixer\Fixer\Whitespace;
  80339. use PhpCsFixer\AbstractFixer;
  80340. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  80341. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  80342. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  80343. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  80344. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  80345. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  80346. use PhpCsFixer\FixerDefinition\CodeSample;
  80347. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80348. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80349. use PhpCsFixer\FixerDefinition\VersionSpecification;
  80350. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  80351. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  80352. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  80353. use PhpCsFixer\Tokenizer\FCT;
  80354. use PhpCsFixer\Tokenizer\Token;
  80355. use PhpCsFixer\Tokenizer\Tokens;
  80356. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  80357. /**
  80358. @phpstan-type
  80359. @phpstan-type
  80360. @implements
  80361. */
  80362. final class TypeDeclarationSpacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  80363. {
  80364. /**
  80365. @use */
  80366. use ConfigurableFixerTrait;
  80367. private const PROPERTY_MODIFIERS = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR, FCT::T_READONLY];
  80368. public function getDefinition(): FixerDefinitionInterface
  80369. {
  80370. return new FixerDefinition(
  80371. 'Ensure single space between a variable and its type declaration in function arguments and properties.',
  80372. [
  80373. new CodeSample(
  80374. '<?php
  80375. class Bar
  80376. {
  80377. private string $a;
  80378. private bool $b;
  80379. public function __invoke(array $c) {}
  80380. }
  80381. '
  80382. ),
  80383. new CodeSample(
  80384. '<?php
  80385. class Foo
  80386. {
  80387. public int $bar;
  80388. public function baz(string $a)
  80389. {
  80390. return fn(bool $c): string => (string) $c;
  80391. }
  80392. }
  80393. ',
  80394. ['elements' => ['function']]
  80395. ),
  80396. new CodeSample(
  80397. '<?php
  80398. class Foo
  80399. {
  80400. public int $bar;
  80401. public function baz(string $a) {}
  80402. }
  80403. ',
  80404. ['elements' => ['property']]
  80405. ),
  80406. new VersionSpecificCodeSample(
  80407. '<?php
  80408. class Foo
  80409. {
  80410. public const string BAR = "";
  80411. }
  80412. ',
  80413. new VersionSpecification(8_03_00),
  80414. ['elements' => ['constant']]
  80415. ),
  80416. ]
  80417. );
  80418. }
  80419. public function isCandidate(Tokens $tokens): bool
  80420. {
  80421. return $tokens->isAnyTokenKindsFound([...Token::getClassyTokenKinds(), T_FN, T_FUNCTION]);
  80422. }
  80423. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  80424. {
  80425. return new FixerConfigurationResolver([
  80426. (new FixerOptionBuilder('elements', 'Structural elements where the spacing after the type declaration should be fixed.'))
  80427. ->setAllowedTypes(['string[]'])
  80428. ->setAllowedValues([new AllowedValueSubset(['function', 'property', 'constant'])])
  80429. ->setDefault(['function', 'property'])
  80430. ->getOption(),
  80431. ]);
  80432. }
  80433. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80434. {
  80435. $functionsAnalyzer = new FunctionsAnalyzer();
  80436. foreach (array_reverse($this->getElements($tokens), true) as $index => $type) {
  80437. if ('property' === $type && \in_array('property', $this->configuration['elements'], true)) {
  80438. $this->ensureSingleSpaceAtPropertyTypehint($tokens, $index);
  80439. continue;
  80440. }
  80441. if ('method' === $type && \in_array('function', $this->configuration['elements'], true)) {
  80442. $this->ensureSingleSpaceAtFunctionArgumentTypehint($functionsAnalyzer, $tokens, $index);
  80443. continue;
  80444. }
  80445. if ('const' === $type && \in_array('constant', $this->configuration['elements'], true)) {
  80446. $this->ensureSingleSpaceAtConstantTypehint($tokens, $index);
  80447. }
  80448. }
  80449. }
  80450. /**
  80451. @phpstan-return
  80452. */
  80453. private function getElements(Tokens $tokens): array
  80454. {
  80455. $tokensAnalyzer = new TokensAnalyzer($tokens);
  80456. $elements = array_map(
  80457. static fn (array $element): string => $element['type'],
  80458. array_filter(
  80459. $tokensAnalyzer->getClassyElements(),
  80460. static fn (array $element): bool => \in_array($element['type'], ['method', 'property', 'const'], true)
  80461. )
  80462. );
  80463. foreach ($tokens as $index => $token) {
  80464. if (
  80465. $token->isGivenKind(T_FN)
  80466. || ($token->isGivenKind(T_FUNCTION) && !isset($elements[$index]))
  80467. ) {
  80468. $elements[$index] = 'method';
  80469. }
  80470. }
  80471. return $elements;
  80472. }
  80473. private function ensureSingleSpaceAtFunctionArgumentTypehint(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index): void
  80474. {
  80475. foreach (array_reverse($functionsAnalyzer->getFunctionArguments($tokens, $index)) as $argumentInfo) {
  80476. $argumentType = $argumentInfo->getTypeAnalysis();
  80477. if (null === $argumentType) {
  80478. continue;
  80479. }
  80480. $tokens->ensureWhitespaceAtIndex($argumentType->getEndIndex() + 1, 0, ' ');
  80481. }
  80482. }
  80483. private function ensureSingleSpaceAtPropertyTypehint(Tokens $tokens, int $index): void
  80484. {
  80485. $propertyIndex = $index;
  80486. do {
  80487. $index = $tokens->getPrevMeaningfulToken($index);
  80488. } while (!$tokens[$index]->isGivenKind(self::PROPERTY_MODIFIERS));
  80489. $propertyType = $this->collectTypeAnalysis($tokens, $index, $propertyIndex);
  80490. if (null === $propertyType) {
  80491. return;
  80492. }
  80493. $tokens->ensureWhitespaceAtIndex($propertyType->getEndIndex() + 1, 0, ' ');
  80494. }
  80495. private function ensureSingleSpaceAtConstantTypehint(Tokens $tokens, int $index): void
  80496. {
  80497. $constIndex = $index;
  80498. $equalsIndex = $tokens->getNextTokenOfKind($constIndex, ['=']);
  80499. if (null === $equalsIndex) {
  80500. return;
  80501. }
  80502. $nameIndex = $tokens->getPrevMeaningfulToken($equalsIndex);
  80503. if (!$tokens[$nameIndex]->isGivenKind(T_STRING)) {
  80504. return;
  80505. }
  80506. $typeEndIndex = $tokens->getPrevMeaningfulToken($nameIndex);
  80507. if (null === $typeEndIndex || $tokens[$typeEndIndex]->isGivenKind(T_CONST)) {
  80508. return;
  80509. }
  80510. $tokens->ensureWhitespaceAtIndex($typeEndIndex + 1, 0, ' ');
  80511. }
  80512. private function collectTypeAnalysis(Tokens $tokens, int $startIndex, int $endIndex): ?TypeAnalysis
  80513. {
  80514. $type = '';
  80515. $typeStartIndex = $tokens->getNextMeaningfulToken($startIndex);
  80516. $typeEndIndex = $typeStartIndex;
  80517. for ($i = $typeStartIndex; $i < $endIndex; ++$i) {
  80518. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  80519. continue;
  80520. }
  80521. $type .= $tokens[$i]->getContent();
  80522. $typeEndIndex = $i;
  80523. }
  80524. return '' !== $type ? new TypeAnalysis($type, $typeStartIndex, $typeEndIndex) : null;
  80525. }
  80526. }
  80527. <?php
  80528. declare(strict_types=1);
  80529. namespace PhpCsFixer\Fixer\Whitespace;
  80530. use PhpCsFixer\AbstractFixer;
  80531. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  80532. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  80533. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  80534. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  80535. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  80536. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  80537. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  80538. use PhpCsFixer\FixerDefinition\CodeSample;
  80539. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80540. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80541. use PhpCsFixer\Tokenizer\Token;
  80542. use PhpCsFixer\Tokenizer\Tokens;
  80543. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  80544. /**
  80545. @phpstan-type
  80546. @phpstan-type
  80547. @implements
  80548. */
  80549. final class BlankLineBeforeStatementFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  80550. {
  80551. /**
  80552. @use */
  80553. use ConfigurableFixerTrait;
  80554. private const TOKEN_MAP = [
  80555. 'break' => T_BREAK,
  80556. 'case' => T_CASE,
  80557. 'continue' => T_CONTINUE,
  80558. 'declare' => T_DECLARE,
  80559. 'default' => T_DEFAULT,
  80560. 'do' => T_DO,
  80561. 'exit' => T_EXIT,
  80562. 'for' => T_FOR,
  80563. 'foreach' => T_FOREACH,
  80564. 'goto' => T_GOTO,
  80565. 'if' => T_IF,
  80566. 'include' => T_INCLUDE,
  80567. 'include_once' => T_INCLUDE_ONCE,
  80568. 'phpdoc' => T_DOC_COMMENT,
  80569. 'require' => T_REQUIRE,
  80570. 'require_once' => T_REQUIRE_ONCE,
  80571. 'return' => T_RETURN,
  80572. 'switch' => T_SWITCH,
  80573. 'throw' => T_THROW,
  80574. 'try' => T_TRY,
  80575. 'while' => T_WHILE,
  80576. 'yield' => T_YIELD,
  80577. 'yield_from' => T_YIELD_FROM,
  80578. ];
  80579. private array $fixTokenMap = [];
  80580. public function getDefinition(): FixerDefinitionInterface
  80581. {
  80582. return new FixerDefinition(
  80583. 'An empty line feed must precede any configured statement.',
  80584. [
  80585. new CodeSample(
  80586. '<?php
  80587. function A() {
  80588. echo 1;
  80589. return 1;
  80590. }
  80591. '
  80592. ),
  80593. new CodeSample(
  80594. '<?php
  80595. switch ($foo) {
  80596. case 42:
  80597. $bar->process();
  80598. break;
  80599. case 44:
  80600. break;
  80601. }
  80602. ',
  80603. [
  80604. 'statements' => ['break'],
  80605. ]
  80606. ),
  80607. new CodeSample(
  80608. '<?php
  80609. foreach ($foo as $bar) {
  80610. if ($bar->isTired()) {
  80611. $bar->sleep();
  80612. continue;
  80613. }
  80614. }
  80615. ',
  80616. [
  80617. 'statements' => ['continue'],
  80618. ]
  80619. ),
  80620. new CodeSample(
  80621. '<?php
  80622. $i = 0;
  80623. do {
  80624. echo $i;
  80625. } while ($i > 0);
  80626. ',
  80627. [
  80628. 'statements' => ['do'],
  80629. ]
  80630. ),
  80631. new CodeSample(
  80632. '<?php
  80633. if ($foo === false) {
  80634. exit(0);
  80635. } else {
  80636. $bar = 9000;
  80637. exit(1);
  80638. }
  80639. ',
  80640. [
  80641. 'statements' => ['exit'],
  80642. ]
  80643. ),
  80644. new CodeSample(
  80645. '<?php
  80646. a:
  80647. if ($foo === false) {
  80648. goto a;
  80649. } else {
  80650. $bar = 9000;
  80651. goto b;
  80652. }
  80653. ',
  80654. [
  80655. 'statements' => ['goto'],
  80656. ]
  80657. ),
  80658. new CodeSample(
  80659. '<?php
  80660. $a = 9000;
  80661. if (true) {
  80662. $foo = $bar;
  80663. }
  80664. ',
  80665. [
  80666. 'statements' => ['if'],
  80667. ]
  80668. ),
  80669. new CodeSample(
  80670. '<?php
  80671. if (true) {
  80672. $foo = $bar;
  80673. return;
  80674. }
  80675. ',
  80676. [
  80677. 'statements' => ['return'],
  80678. ]
  80679. ),
  80680. new CodeSample(
  80681. '<?php
  80682. $a = 9000;
  80683. switch ($a) {
  80684. case 42:
  80685. break;
  80686. }
  80687. ',
  80688. [
  80689. 'statements' => ['switch'],
  80690. ]
  80691. ),
  80692. new CodeSample(
  80693. '<?php
  80694. if (null === $a) {
  80695. $foo->bar();
  80696. throw new \UnexpectedValueException("A cannot be null.");
  80697. }
  80698. ',
  80699. [
  80700. 'statements' => ['throw'],
  80701. ]
  80702. ),
  80703. new CodeSample(
  80704. '<?php
  80705. $a = 9000;
  80706. try {
  80707. $foo->bar();
  80708. } catch (\Exception $exception) {
  80709. $a = -1;
  80710. }
  80711. ',
  80712. [
  80713. 'statements' => ['try'],
  80714. ]
  80715. ),
  80716. new CodeSample(
  80717. '<?php
  80718. function getValues() {
  80719. yield 1;
  80720. yield 2;
  80721. // comment
  80722. yield 3;
  80723. }
  80724. ',
  80725. [
  80726. 'statements' => ['yield'],
  80727. ]
  80728. ),
  80729. ]
  80730. );
  80731. }
  80732. public function getPriority(): int
  80733. {
  80734. return -21;
  80735. }
  80736. public function isCandidate(Tokens $tokens): bool
  80737. {
  80738. return $tokens->isAnyTokenKindsFound($this->fixTokenMap);
  80739. }
  80740. protected function configurePostNormalisation(): void
  80741. {
  80742. $fixTokenMap = [];
  80743. foreach ($this->configuration['statements'] as $key) {
  80744. $fixTokenMap[$key] = self::TOKEN_MAP[$key];
  80745. }
  80746. $this->fixTokenMap = array_values($fixTokenMap);
  80747. }
  80748. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80749. {
  80750. $analyzer = new TokensAnalyzer($tokens);
  80751. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  80752. $token = $tokens[$index];
  80753. if (!$token->isGivenKind($this->fixTokenMap)) {
  80754. continue;
  80755. }
  80756. if ($token->isGivenKind(T_WHILE) && $analyzer->isWhilePartOfDoWhile($index)) {
  80757. continue;
  80758. }
  80759. if ($token->isGivenKind(T_CASE) && $analyzer->isEnumCase($index)) {
  80760. continue;
  80761. }
  80762. $insertBlankLineIndex = $this->getInsertBlankLineIndex($tokens, $index);
  80763. $prevNonWhitespace = $tokens->getPrevNonWhitespace($insertBlankLineIndex);
  80764. if ($this->shouldAddBlankLine($tokens, $prevNonWhitespace)) {
  80765. $this->insertBlankLine($tokens, $insertBlankLineIndex);
  80766. }
  80767. $index = $prevNonWhitespace;
  80768. }
  80769. }
  80770. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  80771. {
  80772. return new FixerConfigurationResolver([
  80773. (new FixerOptionBuilder('statements', 'List of statements which must be preceded by an empty line.'))
  80774. ->setAllowedTypes(['string[]'])
  80775. ->setAllowedValues([new AllowedValueSubset(array_keys(self::TOKEN_MAP))])
  80776. ->setDefault([
  80777. 'break',
  80778. 'continue',
  80779. 'declare',
  80780. 'return',
  80781. 'throw',
  80782. 'try',
  80783. ])
  80784. ->getOption(),
  80785. ]);
  80786. }
  80787. private function getInsertBlankLineIndex(Tokens $tokens, int $index): int
  80788. {
  80789. while ($index > 0) {
  80790. if ($tokens[$index - 1]->isWhitespace() && substr_count($tokens[$index - 1]->getContent(), "\n") > 1) {
  80791. break;
  80792. }
  80793. $prevIndex = $tokens->getPrevNonWhitespace($index);
  80794. if (!$tokens[$prevIndex]->isComment()) {
  80795. break;
  80796. }
  80797. if (!$tokens[$prevIndex - 1]->isWhitespace()) {
  80798. break;
  80799. }
  80800. if (1 !== substr_count($tokens[$prevIndex - 1]->getContent(), "\n")) {
  80801. break;
  80802. }
  80803. $index = $prevIndex;
  80804. }
  80805. return $index;
  80806. }
  80807. private function shouldAddBlankLine(Tokens $tokens, int $prevNonWhitespace): bool
  80808. {
  80809. $prevNonWhitespaceToken = $tokens[$prevNonWhitespace];
  80810. if ($prevNonWhitespaceToken->isComment()) {
  80811. for ($j = $prevNonWhitespace - 1; $j >= 0; --$j) {
  80812. if (str_contains($tokens[$j]->getContent(), "\n")) {
  80813. return false;
  80814. }
  80815. if ($tokens[$j]->isWhitespace() || $tokens[$j]->isComment()) {
  80816. continue;
  80817. }
  80818. return $tokens[$j]->equalsAny([';', '}']);
  80819. }
  80820. }
  80821. return $prevNonWhitespaceToken->equalsAny([';', '}']);
  80822. }
  80823. private function insertBlankLine(Tokens $tokens, int $index): void
  80824. {
  80825. $prevIndex = $index - 1;
  80826. $prevToken = $tokens[$prevIndex];
  80827. $lineEnding = $this->whitespacesConfig->getLineEnding();
  80828. if ($prevToken->isWhitespace()) {
  80829. $newlinesCount = substr_count($prevToken->getContent(), "\n");
  80830. if (0 === $newlinesCount) {
  80831. $tokens[$prevIndex] = new Token([T_WHITESPACE, rtrim($prevToken->getContent(), " \t").$lineEnding.$lineEnding]);
  80832. } elseif (1 === $newlinesCount) {
  80833. $tokens[$prevIndex] = new Token([T_WHITESPACE, $lineEnding.$prevToken->getContent()]);
  80834. }
  80835. } else {
  80836. $tokens->insertAt($index, new Token([T_WHITESPACE, $lineEnding.$lineEnding]));
  80837. }
  80838. }
  80839. }
  80840. <?php
  80841. declare(strict_types=1);
  80842. namespace PhpCsFixer\Fixer\Whitespace;
  80843. use PhpCsFixer\AbstractFixer;
  80844. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  80845. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  80846. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  80847. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  80848. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  80849. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  80850. use PhpCsFixer\FixerDefinition\CodeSample;
  80851. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80852. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80853. use PhpCsFixer\Preg;
  80854. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  80855. use PhpCsFixer\Tokenizer\Token;
  80856. use PhpCsFixer\Tokenizer\Tokens;
  80857. /**
  80858. @phpstan-type
  80859. @phpstan-type
  80860. @implements
  80861. */
  80862. final class HeredocIndentationFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  80863. {
  80864. /**
  80865. @use */
  80866. use ConfigurableFixerTrait;
  80867. public function getDefinition(): FixerDefinitionInterface
  80868. {
  80869. return new FixerDefinition(
  80870. 'Heredoc/nowdoc content must be properly indented.',
  80871. [
  80872. new CodeSample(
  80873. <<<'SAMPLE'
  80874. <?php
  80875. $heredoc = <<<EOD
  80876. abc
  80877. def
  80878. EOD;
  80879. $nowdoc = <<<'EOD'
  80880. abc
  80881. def
  80882. EOD;
  80883. SAMPLE
  80884. ),
  80885. new CodeSample(
  80886. <<<'SAMPLE'
  80887. <?php
  80888. $nowdoc = <<<'EOD'
  80889. abc
  80890. def
  80891. EOD;
  80892. SAMPLE
  80893. ,
  80894. ['indentation' => 'same_as_start']
  80895. ),
  80896. ]
  80897. );
  80898. }
  80899. public function getPriority(): int
  80900. {
  80901. return -26;
  80902. }
  80903. public function isCandidate(Tokens $tokens): bool
  80904. {
  80905. return $tokens->isTokenKindFound(T_START_HEREDOC);
  80906. }
  80907. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  80908. {
  80909. return new FixerConfigurationResolver([
  80910. (new FixerOptionBuilder('indentation', 'Whether the indentation should be the same as in the start token line or one level more.'))
  80911. ->setAllowedValues(['start_plus_one', 'same_as_start'])
  80912. ->setDefault('start_plus_one')
  80913. ->getOption(),
  80914. ]);
  80915. }
  80916. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  80917. {
  80918. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  80919. if (!$tokens[$index]->isGivenKind(T_END_HEREDOC)) {
  80920. continue;
  80921. }
  80922. $end = $index;
  80923. $index = $tokens->getPrevTokenOfKind($index, [[T_START_HEREDOC]]);
  80924. $this->fixIndentation($tokens, $index, $end);
  80925. }
  80926. }
  80927. private function fixIndentation(Tokens $tokens, int $start, int $end): void
  80928. {
  80929. $indent = WhitespacesAnalyzer::detectIndent($tokens, $start);
  80930. if ('start_plus_one' === $this->configuration['indentation']) {
  80931. $indent .= $this->whitespacesConfig->getIndent();
  80932. }
  80933. Preg::match('/^\h*/', $tokens[$end]->getContent(), $matches);
  80934. $currentIndent = $matches[0];
  80935. $currentIndentLength = \strlen($currentIndent);
  80936. $content = $indent.substr($tokens[$end]->getContent(), $currentIndentLength);
  80937. $tokens[$end] = new Token([T_END_HEREDOC, $content]);
  80938. if ($end === $start + 1) {
  80939. return;
  80940. }
  80941. $index = $end - 1;
  80942. for ($last = true; $index > $start; --$index, $last = false) {
  80943. if (!$tokens[$index]->isGivenKind([T_ENCAPSED_AND_WHITESPACE, T_WHITESPACE])) {
  80944. continue;
  80945. }
  80946. $content = $tokens[$index]->getContent();
  80947. if ('' !== $currentIndent) {
  80948. $content = Preg::replace('/(?<=\v)(?!'.$currentIndent.')\h+/', '', $content);
  80949. }
  80950. $regexEnd = $last && '' === $currentIndent ? '(?!\v|$)' : '(?!\v)';
  80951. $content = Preg::replace('/(?<=\v)'.$currentIndent.$regexEnd.'/', $indent, $content);
  80952. $tokens[$index] = new Token([$tokens[$index]->getId(), $content]);
  80953. }
  80954. ++$index;
  80955. if (!$tokens[$index]->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  80956. $tokens->insertAt($index, new Token([T_ENCAPSED_AND_WHITESPACE, $indent]));
  80957. return;
  80958. }
  80959. $content = $tokens[$index]->getContent();
  80960. if (!\in_array($content[0], ["\r", "\n"], true) && ('' === $currentIndent || str_starts_with($content, $currentIndent))) {
  80961. $content = $indent.substr($content, $currentIndentLength);
  80962. } elseif ('' !== $currentIndent) {
  80963. $content = Preg::replace('/^(?!'.$currentIndent.')\h+/', '', $content);
  80964. }
  80965. $tokens[$index] = new Token([T_ENCAPSED_AND_WHITESPACE, $content]);
  80966. }
  80967. }
  80968. <?php
  80969. declare(strict_types=1);
  80970. namespace PhpCsFixer\Fixer\Whitespace;
  80971. use PhpCsFixer\AbstractFixer;
  80972. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  80973. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  80974. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  80975. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  80976. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  80977. use PhpCsFixer\FixerDefinition\CodeSample;
  80978. use PhpCsFixer\FixerDefinition\FixerDefinition;
  80979. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  80980. use PhpCsFixer\FixerDefinition\VersionSpecification;
  80981. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  80982. use PhpCsFixer\Preg;
  80983. use PhpCsFixer\Tokenizer\CT;
  80984. use PhpCsFixer\Tokenizer\Token;
  80985. use PhpCsFixer\Tokenizer\Tokens;
  80986. /**
  80987. @phpstan-type
  80988. @phpstan-type
  80989. @implements
  80990. */
  80991. final class TypesSpacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  80992. {
  80993. /**
  80994. @use */
  80995. use ConfigurableFixerTrait;
  80996. public function getDefinition(): FixerDefinitionInterface
  80997. {
  80998. return new FixerDefinition(
  80999. 'A single space or none should be around union type and intersection type operators.',
  81000. [
  81001. new CodeSample(
  81002. "<?php\ntry\n{\n new Foo();\n} catch (ErrorA | ErrorB \$e) {\necho'error';}\n"
  81003. ),
  81004. new CodeSample(
  81005. "<?php\ntry\n{\n new Foo();\n} catch (ErrorA|ErrorB \$e) {\necho'error';}\n",
  81006. ['space' => 'single']
  81007. ),
  81008. new VersionSpecificCodeSample(
  81009. "<?php\nfunction foo(int | string \$x)\n{\n}\n",
  81010. new VersionSpecification(8_00_00)
  81011. ),
  81012. ]
  81013. );
  81014. }
  81015. public function getPriority(): int
  81016. {
  81017. return -1;
  81018. }
  81019. public function isCandidate(Tokens $tokens): bool
  81020. {
  81021. return $tokens->isAnyTokenKindsFound([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION]);
  81022. }
  81023. protected function configurePostNormalisation(): void
  81024. {
  81025. if (!isset($this->configuration['space_multiple_catch'])) {
  81026. $this->configuration = [
  81027. 'space' => $this->configuration['space'],
  81028. 'space_multiple_catch' => $this->configuration['space'],
  81029. ];
  81030. }
  81031. }
  81032. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  81033. {
  81034. return new FixerConfigurationResolver([
  81035. (new FixerOptionBuilder('space', 'Spacing to apply around union type and intersection type operators.'))
  81036. ->setAllowedValues(['none', 'single'])
  81037. ->setDefault('none')
  81038. ->getOption(),
  81039. (new FixerOptionBuilder('space_multiple_catch', 'Spacing to apply around type operator when catching exceptions of multiple types, use `null` to follow the value configured for `space`.'))
  81040. ->setAllowedValues(['none', 'single', null])
  81041. ->setDefault(null)
  81042. ->getOption(),
  81043. ]);
  81044. }
  81045. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81046. {
  81047. $tokenCount = $tokens->count() - 1;
  81048. for ($index = 0; $index < $tokenCount; ++$index) {
  81049. if ($tokens[$index]->isGivenKind([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION])) {
  81050. $tokenCount += $this->fixSpacing($tokens, $index, 'single' === $this->configuration['space']);
  81051. continue;
  81052. }
  81053. if ($tokens[$index]->isGivenKind(T_CATCH)) {
  81054. while (true) {
  81055. $index = $tokens->getNextTokenOfKind($index, [')', [CT::T_TYPE_ALTERNATION]]);
  81056. if ($tokens[$index]->equals(')')) {
  81057. break;
  81058. }
  81059. $tokenCount += $this->fixSpacing($tokens, $index, 'single' === $this->configuration['space_multiple_catch']);
  81060. }
  81061. }
  81062. }
  81063. }
  81064. private function fixSpacing(Tokens $tokens, int $index, bool $singleSpace): int
  81065. {
  81066. if (!$singleSpace) {
  81067. $this->ensureNoSpace($tokens, $index + 1);
  81068. $this->ensureNoSpace($tokens, $index - 1);
  81069. return 0;
  81070. }
  81071. $addedTokenCount = 0;
  81072. $addedTokenCount += $this->ensureSingleSpace($tokens, $index + 1, 0);
  81073. $addedTokenCount += $this->ensureSingleSpace($tokens, $index - 1, 1);
  81074. return $addedTokenCount;
  81075. }
  81076. private function ensureSingleSpace(Tokens $tokens, int $index, int $offset): int
  81077. {
  81078. if (!$tokens[$index]->isWhitespace()) {
  81079. $tokens->insertSlices([$index + $offset => new Token([T_WHITESPACE, ' '])]);
  81080. return 1;
  81081. }
  81082. if (' ' !== $tokens[$index]->getContent() && !Preg::match('/\R/', $tokens[$index]->getContent())) {
  81083. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  81084. }
  81085. return 0;
  81086. }
  81087. private function ensureNoSpace(Tokens $tokens, int $index): void
  81088. {
  81089. if ($tokens[$index]->isWhitespace() && !Preg::match('/\R/', $tokens[$index]->getContent())) {
  81090. $tokens->clearAt($index);
  81091. }
  81092. }
  81093. }
  81094. <?php
  81095. declare(strict_types=1);
  81096. namespace PhpCsFixer\Fixer\Whitespace;
  81097. use PhpCsFixer\AbstractFixer;
  81098. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  81099. use PhpCsFixer\FixerDefinition\CodeSample;
  81100. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81101. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81102. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  81103. use PhpCsFixer\Tokenizer\CT;
  81104. use PhpCsFixer\Tokenizer\Tokens;
  81105. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  81106. final class BlankLineBetweenImportGroupsFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  81107. {
  81108. private const IMPORT_TYPE_CLASS = 'class';
  81109. private const IMPORT_TYPE_CONST = 'const';
  81110. private const IMPORT_TYPE_FUNCTION = 'function';
  81111. public function getDefinition(): FixerDefinitionInterface
  81112. {
  81113. return new FixerDefinition(
  81114. 'Putting blank lines between `use` statement groups.',
  81115. [
  81116. new CodeSample(
  81117. '<?php
  81118. use function AAC;
  81119. use const AAB;
  81120. use AAA;
  81121. '
  81122. ),
  81123. new CodeSample(
  81124. '<?php
  81125. use const AAAA;
  81126. use const BBB;
  81127. use Bar;
  81128. use AAC;
  81129. use Acme;
  81130. use function CCC\AA;
  81131. use function DDD;
  81132. '
  81133. ),
  81134. new CodeSample(
  81135. '<?php
  81136. use const BBB;
  81137. use const AAAA;
  81138. use Acme;
  81139. use AAC;
  81140. use Bar;
  81141. use function DDD;
  81142. use function CCC\AA;
  81143. '
  81144. ),
  81145. new CodeSample(
  81146. '<?php
  81147. use const AAAA;
  81148. use const BBB;
  81149. use Acme;
  81150. use function DDD;
  81151. use AAC;
  81152. use function CCC\AA;
  81153. use Bar;
  81154. '
  81155. ),
  81156. ]
  81157. );
  81158. }
  81159. public function getPriority(): int
  81160. {
  81161. return -40;
  81162. }
  81163. public function isCandidate(Tokens $tokens): bool
  81164. {
  81165. return $tokens->isTokenKindFound(T_USE);
  81166. }
  81167. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81168. {
  81169. $tokensAnalyzer = new TokensAnalyzer($tokens);
  81170. $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
  81171. foreach (array_reverse($namespacesImports) as $uses) {
  81172. $this->walkOverUses($tokens, $uses);
  81173. }
  81174. }
  81175. private function walkOverUses(Tokens $tokens, array $uses): void
  81176. {
  81177. $usesCount = \count($uses);
  81178. if ($usesCount < 2) {
  81179. return;
  81180. }
  81181. $previousType = null;
  81182. for ($i = $usesCount - 1; $i >= 0; --$i) {
  81183. $index = $uses[$i];
  81184. $startIndex = $tokens->getNextMeaningfulToken($index + 1);
  81185. $endIndex = $tokens->getNextTokenOfKind($startIndex, [';', [T_CLOSE_TAG]]);
  81186. if ($tokens[$startIndex]->isGivenKind(CT::T_CONST_IMPORT)) {
  81187. $type = self::IMPORT_TYPE_CONST;
  81188. } elseif ($tokens[$startIndex]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  81189. $type = self::IMPORT_TYPE_FUNCTION;
  81190. } else {
  81191. $type = self::IMPORT_TYPE_CLASS;
  81192. }
  81193. if (null !== $previousType && $type !== $previousType) {
  81194. $this->ensureLine($tokens, $endIndex + 1);
  81195. }
  81196. $previousType = $type;
  81197. }
  81198. }
  81199. private function ensureLine(Tokens $tokens, int $index): void
  81200. {
  81201. static $lineEnding;
  81202. if (null === $lineEnding) {
  81203. $lineEnding = $this->whitespacesConfig->getLineEnding();
  81204. $lineEnding .= $lineEnding;
  81205. }
  81206. $index = $this->getInsertIndex($tokens, $index);
  81207. $indent = WhitespacesAnalyzer::detectIndent($tokens, $index);
  81208. $tokens->ensureWhitespaceAtIndex($index, 1, $lineEnding.$indent);
  81209. }
  81210. private function getInsertIndex(Tokens $tokens, int $index): int
  81211. {
  81212. $tokensCount = \count($tokens);
  81213. for (; $index < $tokensCount - 1; ++$index) {
  81214. if (!$tokens[$index]->isWhitespace() && !$tokens[$index]->isComment()) {
  81215. return $index - 1;
  81216. }
  81217. $content = $tokens[$index]->getContent();
  81218. if (str_contains($content, "\n")) {
  81219. return $index;
  81220. }
  81221. }
  81222. return $index;
  81223. }
  81224. }
  81225. <?php
  81226. declare(strict_types=1);
  81227. namespace PhpCsFixer\Fixer\Whitespace;
  81228. use PhpCsFixer\AbstractProxyFixer;
  81229. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  81230. use PhpCsFixer\FixerDefinition\CodeSample;
  81231. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81232. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81233. use PhpCsFixer\Tokenizer\Tokens;
  81234. final class NoSpacesInsideParenthesisFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  81235. {
  81236. public function getDefinition(): FixerDefinitionInterface
  81237. {
  81238. return new FixerDefinition(
  81239. 'There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis.',
  81240. [
  81241. new CodeSample("<?php\nif ( \$a ) {\n foo( );\n}\n"),
  81242. new CodeSample(
  81243. "<?php
  81244. function foo( \$bar, \$baz )
  81245. {
  81246. }\n"
  81247. ),
  81248. ]
  81249. );
  81250. }
  81251. public function getPriority(): int
  81252. {
  81253. return 3;
  81254. }
  81255. public function getSuccessorsNames(): array
  81256. {
  81257. return array_keys($this->proxyFixers);
  81258. }
  81259. public function isCandidate(Tokens $tokens): bool
  81260. {
  81261. return $tokens->isTokenKindFound('(');
  81262. }
  81263. protected function createProxyFixers(): array
  81264. {
  81265. return [new SpacesInsideParenthesesFixer()];
  81266. }
  81267. }
  81268. <?php
  81269. declare(strict_types=1);
  81270. namespace PhpCsFixer\Fixer\Whitespace;
  81271. use PhpCsFixer\AbstractFixer;
  81272. use PhpCsFixer\FixerDefinition\CodeSample;
  81273. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81274. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81275. use PhpCsFixer\Preg;
  81276. use PhpCsFixer\Tokenizer\Token;
  81277. use PhpCsFixer\Tokenizer\Tokens;
  81278. final class NoTrailingWhitespaceFixer extends AbstractFixer
  81279. {
  81280. public function getDefinition(): FixerDefinitionInterface
  81281. {
  81282. return new FixerDefinition(
  81283. 'Remove trailing whitespace at the end of non-blank lines.',
  81284. [new CodeSample("<?php\n\$a = 1; \n")]
  81285. );
  81286. }
  81287. public function getPriority(): int
  81288. {
  81289. return 0;
  81290. }
  81291. public function isCandidate(Tokens $tokens): bool
  81292. {
  81293. return true;
  81294. }
  81295. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81296. {
  81297. for ($index = \count($tokens) - 1; $index >= 0; --$index) {
  81298. $token = $tokens[$index];
  81299. if (
  81300. $token->isGivenKind(T_OPEN_TAG)
  81301. && $tokens->offsetExists($index + 1)
  81302. && $tokens[$index + 1]->isWhitespace()
  81303. && Preg::match('/(.*)\h$/', $token->getContent(), $openTagMatches)
  81304. && Preg::match('/^(\R)(.*)$/s', $tokens[$index + 1]->getContent(), $whitespaceMatches)
  81305. ) {
  81306. $tokens[$index] = new Token([T_OPEN_TAG, $openTagMatches[1].$whitespaceMatches[1]]);
  81307. $tokens->ensureWhitespaceAtIndex($index + 1, 0, $whitespaceMatches[2]);
  81308. continue;
  81309. }
  81310. if (!$token->isWhitespace()) {
  81311. continue;
  81312. }
  81313. $lines = Preg::split('/(\R+)/', $token->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE);
  81314. $linesSize = \count($lines);
  81315. if ($linesSize > 1 || !isset($tokens[$index + 1])) {
  81316. if (!$tokens[$index - 1]->isGivenKind(T_OPEN_TAG) || !Preg::match('/(.*)\R$/', $tokens[$index - 1]->getContent())) {
  81317. $lines[0] = rtrim($lines[0], " \t");
  81318. }
  81319. for ($i = 1; $i < $linesSize; ++$i) {
  81320. $trimmedLine = rtrim($lines[$i], " \t");
  81321. if ('' !== $trimmedLine) {
  81322. $lines[$i] = $trimmedLine;
  81323. }
  81324. }
  81325. $content = implode('', $lines);
  81326. if ('' !== $content) {
  81327. $tokens[$index] = new Token([$token->getId(), $content]);
  81328. } else {
  81329. $tokens->clearAt($index);
  81330. }
  81331. }
  81332. }
  81333. }
  81334. }
  81335. <?php
  81336. declare(strict_types=1);
  81337. namespace PhpCsFixer\Fixer\Whitespace;
  81338. use PhpCsFixer\AbstractFixer;
  81339. use PhpCsFixer\FixerDefinition\CodeSample;
  81340. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81341. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81342. use PhpCsFixer\Tokenizer\CT;
  81343. use PhpCsFixer\Tokenizer\Tokens;
  81344. final class CompactNullableTypeDeclarationFixer extends AbstractFixer
  81345. {
  81346. public function getDefinition(): FixerDefinitionInterface
  81347. {
  81348. return new FixerDefinition(
  81349. 'Remove extra spaces in a nullable type declaration.',
  81350. [
  81351. new CodeSample(
  81352. "<?php\nfunction sample(? string \$str): ? string\n{}\n"
  81353. ),
  81354. ],
  81355. 'Rule is applied only in a PHP 7.1+ environment.'
  81356. );
  81357. }
  81358. public function isCandidate(Tokens $tokens): bool
  81359. {
  81360. return $tokens->isTokenKindFound(CT::T_NULLABLE_TYPE);
  81361. }
  81362. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81363. {
  81364. static $typehintKinds = [
  81365. CT::T_ARRAY_TYPEHINT,
  81366. T_CALLABLE,
  81367. T_NS_SEPARATOR,
  81368. T_STATIC,
  81369. T_STRING,
  81370. ];
  81371. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  81372. if (!$tokens[$index]->isGivenKind(CT::T_NULLABLE_TYPE)) {
  81373. continue;
  81374. }
  81375. if (
  81376. $tokens[$index + 1]->isWhitespace()
  81377. && $tokens[$index + 2]->isGivenKind($typehintKinds)
  81378. ) {
  81379. $tokens->removeTrailingWhitespace($index);
  81380. }
  81381. }
  81382. }
  81383. }
  81384. <?php
  81385. declare(strict_types=1);
  81386. namespace PhpCsFixer\Fixer\Whitespace;
  81387. use PhpCsFixer\AbstractFixer;
  81388. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  81389. use PhpCsFixer\FixerDefinition\CodeSample;
  81390. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81391. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81392. use PhpCsFixer\Preg;
  81393. use PhpCsFixer\Tokenizer\Token;
  81394. use PhpCsFixer\Tokenizer\Tokens;
  81395. final class MethodChainingIndentationFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  81396. {
  81397. public function getDefinition(): FixerDefinitionInterface
  81398. {
  81399. return new FixerDefinition(
  81400. 'Method chaining MUST be properly indented. Method chaining with different levels of indentation is not supported.',
  81401. [new CodeSample("<?php\n\$user->setEmail('voff.web@gmail.com')\n ->setPassword('233434');\n")]
  81402. );
  81403. }
  81404. public function getPriority(): int
  81405. {
  81406. return 0;
  81407. }
  81408. public function isCandidate(Tokens $tokens): bool
  81409. {
  81410. return $tokens->isAnyTokenKindsFound(Token::getObjectOperatorKinds());
  81411. }
  81412. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81413. {
  81414. $lineEnding = $this->whitespacesConfig->getLineEnding();
  81415. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  81416. if (!$tokens[$index]->isObjectOperator()) {
  81417. continue;
  81418. }
  81419. $endParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(', ';', ',', [T_CLOSE_TAG]]);
  81420. $previousEndParenthesisIndex = $tokens->getPrevTokenOfKind($index, [')']);
  81421. if (
  81422. null === $endParenthesisIndex
  81423. || !$tokens[$endParenthesisIndex]->equals('(') && null === $previousEndParenthesisIndex
  81424. ) {
  81425. continue;
  81426. }
  81427. if ($this->canBeMovedToNextLine($index, $tokens)) {
  81428. $newline = new Token([T_WHITESPACE, $lineEnding]);
  81429. if ($tokens[$index - 1]->isWhitespace()) {
  81430. $tokens[$index - 1] = $newline;
  81431. } else {
  81432. $tokens->insertAt($index, $newline);
  81433. ++$index;
  81434. ++$endParenthesisIndex;
  81435. }
  81436. }
  81437. $currentIndent = $this->getIndentAt($tokens, $index - 1);
  81438. if (null === $currentIndent) {
  81439. continue;
  81440. }
  81441. $expectedIndent = $this->getExpectedIndentAt($tokens, $index);
  81442. if ($currentIndent !== $expectedIndent) {
  81443. $tokens[$index - 1] = new Token([T_WHITESPACE, $lineEnding.$expectedIndent]);
  81444. }
  81445. if (!$tokens[$endParenthesisIndex]->equals('(')) {
  81446. continue;
  81447. }
  81448. $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endParenthesisIndex);
  81449. for ($searchIndex = $index + 1; $searchIndex < $endParenthesisIndex; ++$searchIndex) {
  81450. $searchToken = $tokens[$searchIndex];
  81451. if (!$searchToken->isWhitespace()) {
  81452. continue;
  81453. }
  81454. $content = $searchToken->getContent();
  81455. if (!Preg::match('/\R/', $content)) {
  81456. continue;
  81457. }
  81458. $content = Preg::replace(
  81459. '/(\R)'.$currentIndent.'(\h*)$/D',
  81460. '$1'.$expectedIndent.'$2',
  81461. $content
  81462. );
  81463. $tokens[$searchIndex] = new Token([$searchToken->getId(), $content]);
  81464. }
  81465. }
  81466. }
  81467. private function getExpectedIndentAt(Tokens $tokens, int $index): string
  81468. {
  81469. $index = $tokens->getPrevMeaningfulToken($index);
  81470. $indent = $this->whitespacesConfig->getIndent();
  81471. for ($i = $index; $i >= 0; --$i) {
  81472. if ($tokens[$i]->equals(')')) {
  81473. $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  81474. }
  81475. $currentIndent = $this->getIndentAt($tokens, $i);
  81476. if (null === $currentIndent) {
  81477. continue;
  81478. }
  81479. if ($this->currentLineRequiresExtraIndentLevel($tokens, $i, $index)) {
  81480. return $currentIndent.$indent;
  81481. }
  81482. return $currentIndent;
  81483. }
  81484. return $indent;
  81485. }
  81486. private function canBeMovedToNextLine(int $index, Tokens $tokens): bool
  81487. {
  81488. $prevMeaningful = $tokens->getPrevMeaningfulToken($index);
  81489. $hasCommentBefore = false;
  81490. for ($i = $index - 1; $i > $prevMeaningful; --$i) {
  81491. if ($tokens[$i]->isComment()) {
  81492. $hasCommentBefore = true;
  81493. continue;
  81494. }
  81495. if ($tokens[$i]->isWhitespace() && Preg::match('/\R/', $tokens[$i]->getContent())) {
  81496. return $hasCommentBefore;
  81497. }
  81498. }
  81499. return false;
  81500. }
  81501. private function getIndentAt(Tokens $tokens, int $index): ?string
  81502. {
  81503. if (Preg::match('/\R{1}(\h*)$/', $this->getIndentContentAt($tokens, $index), $matches)) {
  81504. return $matches[1];
  81505. }
  81506. return null;
  81507. }
  81508. private function getIndentContentAt(Tokens $tokens, int $index): string
  81509. {
  81510. if (!$tokens[$index]->isGivenKind([T_WHITESPACE, T_INLINE_HTML])) {
  81511. return '';
  81512. }
  81513. $content = $tokens[$index]->getContent();
  81514. if ($tokens[$index]->isWhitespace() && $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)) {
  81515. $content = $tokens[$index - 1]->getContent().$content;
  81516. }
  81517. if (Preg::match('/\R/', $content)) {
  81518. return $content;
  81519. }
  81520. return '';
  81521. }
  81522. private function currentLineRequiresExtraIndentLevel(Tokens $tokens, int $start, int $end): bool
  81523. {
  81524. $firstMeaningful = $tokens->getNextMeaningfulToken($start);
  81525. if ($tokens[$firstMeaningful]->isObjectOperator()) {
  81526. $thirdMeaningful = $tokens->getNextMeaningfulToken($tokens->getNextMeaningfulToken($firstMeaningful));
  81527. return
  81528. $tokens[$thirdMeaningful]->equals('(')
  81529. && $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $thirdMeaningful) > $end;
  81530. }
  81531. return
  81532. !$tokens[$end]->equals(')')
  81533. || $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $end) >= $start;
  81534. }
  81535. }
  81536. <?php
  81537. declare(strict_types=1);
  81538. namespace PhpCsFixer\Fixer\Whitespace;
  81539. use PhpCsFixer\AbstractFixer;
  81540. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  81541. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  81542. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  81543. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  81544. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  81545. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  81546. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  81547. use PhpCsFixer\FixerDefinition\CodeSample;
  81548. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81549. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81550. use PhpCsFixer\Preg;
  81551. use PhpCsFixer\Tokenizer\Analyzer\SwitchAnalyzer;
  81552. use PhpCsFixer\Tokenizer\CT;
  81553. use PhpCsFixer\Tokenizer\FCT;
  81554. use PhpCsFixer\Tokenizer\Token;
  81555. use PhpCsFixer\Tokenizer\Tokens;
  81556. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  81557. use PhpCsFixer\Utils;
  81558. /**
  81559. @phpstan-type
  81560. @phpstan-type
  81561. @implements
  81562. */
  81563. final class NoExtraBlankLinesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  81564. {
  81565. /**
  81566. @use */
  81567. use ConfigurableFixerTrait;
  81568. private const AVAILABLE_TOKENS = [
  81569. 'attribute',
  81570. 'break',
  81571. 'case',
  81572. 'comma',
  81573. 'continue',
  81574. 'curly_brace_block',
  81575. 'default',
  81576. 'extra',
  81577. 'parenthesis_brace_block',
  81578. 'return',
  81579. 'square_brace_block',
  81580. 'switch',
  81581. 'throw',
  81582. 'use',
  81583. 'use_trait',
  81584. ];
  81585. private array $tokenKindCallbackMap;
  81586. private array $tokenEqualsMap;
  81587. private Tokens $tokens;
  81588. private TokensAnalyzer $tokensAnalyzer;
  81589. public function getDefinition(): FixerDefinitionInterface
  81590. {
  81591. return new FixerDefinition(
  81592. 'Removes extra blank lines and/or blank lines following configuration.',
  81593. [
  81594. new CodeSample(
  81595. '<?php
  81596. $foo = array("foo");
  81597. $bar = "bar";
  81598. '
  81599. ),
  81600. new CodeSample(
  81601. '<?php
  81602. switch ($foo) {
  81603. case 41:
  81604. echo "foo";
  81605. break;
  81606. case 42:
  81607. break;
  81608. }
  81609. ',
  81610. ['tokens' => ['break']]
  81611. ),
  81612. new CodeSample(
  81613. '<?php
  81614. for ($i = 0; $i < 9000; ++$i) {
  81615. if (true) {
  81616. continue;
  81617. }
  81618. }
  81619. ',
  81620. ['tokens' => ['continue']]
  81621. ),
  81622. new CodeSample(
  81623. '<?php
  81624. for ($i = 0; $i < 9000; ++$i) {
  81625. echo $i;
  81626. }
  81627. ',
  81628. ['tokens' => ['curly_brace_block']]
  81629. ),
  81630. new CodeSample(
  81631. '<?php
  81632. $foo = array("foo");
  81633. $bar = "bar";
  81634. ',
  81635. ['tokens' => ['extra']]
  81636. ),
  81637. new CodeSample(
  81638. '<?php
  81639. $foo = array(
  81640. "foo"
  81641. );
  81642. ',
  81643. ['tokens' => ['parenthesis_brace_block']]
  81644. ),
  81645. new CodeSample(
  81646. '<?php
  81647. function foo($bar)
  81648. {
  81649. return $bar;
  81650. }
  81651. ',
  81652. ['tokens' => ['return']]
  81653. ),
  81654. new CodeSample(
  81655. '<?php
  81656. $foo = [
  81657. "foo"
  81658. ];
  81659. ',
  81660. ['tokens' => ['square_brace_block']]
  81661. ),
  81662. new CodeSample(
  81663. '<?php
  81664. function foo($bar)
  81665. {
  81666. throw new \Exception("Hello!");
  81667. }
  81668. ',
  81669. ['tokens' => ['throw']]
  81670. ),
  81671. new CodeSample(
  81672. '<?php
  81673. namespace Foo;
  81674. use Bar\Baz;
  81675. use Baz\Bar;
  81676. class Bar
  81677. {
  81678. }
  81679. ',
  81680. ['tokens' => ['use']]
  81681. ),
  81682. new CodeSample(
  81683. '<?php
  81684. switch($a) {
  81685. case 1:
  81686. default:
  81687. echo 3;
  81688. }
  81689. ',
  81690. ['tokens' => ['switch', 'case', 'default']]
  81691. ),
  81692. ]
  81693. );
  81694. }
  81695. public function getPriority(): int
  81696. {
  81697. return -20;
  81698. }
  81699. public function isCandidate(Tokens $tokens): bool
  81700. {
  81701. return true;
  81702. }
  81703. protected function configurePreNormalisation(array $configuration): void
  81704. {
  81705. if (isset($configuration['tokens']) && \in_array('use_trait', $configuration['tokens'], true)) {
  81706. Utils::triggerDeprecation(new \RuntimeException('Option "tokens: use_trait" used in `no_extra_blank_lines` rule is deprecated, use the rule `class_attributes_separation` with `elements: trait_import` instead.'));
  81707. }
  81708. }
  81709. protected function configurePostNormalisation(): void
  81710. {
  81711. $tokensConfiguration = $this->configuration['tokens'];
  81712. $this->tokenEqualsMap = [];
  81713. if (\in_array('comma', $tokensConfiguration, true)) {
  81714. $this->tokenEqualsMap[','] = [$this, 'fixAfterToken'];
  81715. }
  81716. if (\in_array('curly_brace_block', $tokensConfiguration, true)) {
  81717. $this->tokenEqualsMap['{'] = [$this, 'fixStructureOpenCloseIfMultiLine'];
  81718. }
  81719. if (\in_array('parenthesis_brace_block', $tokensConfiguration, true)) {
  81720. $this->tokenEqualsMap['('] = [$this, 'fixStructureOpenCloseIfMultiLine'];
  81721. }
  81722. $configMap = [
  81723. 'attribute' => [CT::T_ATTRIBUTE_CLOSE, [$this, 'fixAfterToken']],
  81724. 'break' => [T_BREAK, [$this, 'fixAfterToken']],
  81725. 'case' => [T_CASE, [$this, 'fixAfterCaseToken']],
  81726. 'continue' => [T_CONTINUE, [$this, 'fixAfterToken']],
  81727. 'default' => [T_DEFAULT, [$this, 'fixAfterToken']],
  81728. 'extra' => [T_WHITESPACE, [$this, 'removeMultipleBlankLines']],
  81729. 'return' => [T_RETURN, [$this, 'fixAfterToken']],
  81730. 'square_brace_block' => [CT::T_ARRAY_SQUARE_BRACE_OPEN, [$this, 'fixStructureOpenCloseIfMultiLine']],
  81731. 'switch' => [T_SWITCH, [$this, 'fixAfterToken']],
  81732. 'throw' => [T_THROW, [$this, 'fixAfterThrowToken']],
  81733. 'use' => [T_USE, [$this, 'removeBetweenUse']],
  81734. 'use_trait' => [CT::T_USE_TRAIT, [$this, 'removeBetweenUse']],
  81735. ];
  81736. $this->tokenKindCallbackMap = [];
  81737. foreach ($tokensConfiguration as $config) {
  81738. if (isset($configMap[$config])) {
  81739. $this->tokenKindCallbackMap[$configMap[$config][0]] = $configMap[$config][1];
  81740. }
  81741. }
  81742. }
  81743. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  81744. {
  81745. $this->tokens = $tokens;
  81746. $this->tokensAnalyzer = new TokensAnalyzer($this->tokens);
  81747. for ($index = $tokens->getSize() - 1; $index > 0; --$index) {
  81748. $this->fixByToken($tokens[$index], $index);
  81749. }
  81750. }
  81751. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  81752. {
  81753. return new FixerConfigurationResolver([
  81754. (new FixerOptionBuilder('tokens', 'List of tokens to fix.'))
  81755. ->setAllowedTypes(['string[]'])
  81756. ->setAllowedValues([new AllowedValueSubset(self::AVAILABLE_TOKENS)])
  81757. ->setDefault(['extra'])
  81758. ->getOption(),
  81759. ]);
  81760. }
  81761. private function fixByToken(Token $token, int $index): void
  81762. {
  81763. foreach ($this->tokenKindCallbackMap as $kind => $callback) {
  81764. if (!$token->isGivenKind($kind)) {
  81765. continue;
  81766. }
  81767. \call_user_func_array($this->tokenKindCallbackMap[$token->getId()], [$index]);
  81768. return;
  81769. }
  81770. foreach ($this->tokenEqualsMap as $equals => $callback) {
  81771. if (!$token->equals($equals)) {
  81772. continue;
  81773. }
  81774. \call_user_func_array($this->tokenEqualsMap[$token->getContent()], [$index]);
  81775. return;
  81776. }
  81777. }
  81778. private function removeBetweenUse(int $index): void
  81779. {
  81780. $next = $this->tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  81781. if (null === $next || $this->tokens[$next]->isGivenKind(T_CLOSE_TAG)) {
  81782. return;
  81783. }
  81784. $nextUseCandidate = $this->tokens->getNextMeaningfulToken($next);
  81785. if (null === $nextUseCandidate || !$this->tokens[$nextUseCandidate]->isGivenKind($this->tokens[$index]->getId()) || !$this->containsLinebreak($index, $nextUseCandidate)) {
  81786. return;
  81787. }
  81788. $this->removeEmptyLinesAfterLineWithTokenAt($next);
  81789. }
  81790. private function removeMultipleBlankLines(int $index): void
  81791. {
  81792. $expected = $this->tokens[$index - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R$/', $this->tokens[$index - 1]->getContent()) ? 1 : 2;
  81793. $parts = Preg::split('/(.*\R)/', $this->tokens[$index]->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  81794. $count = \count($parts);
  81795. if ($count > $expected) {
  81796. $this->tokens[$index] = new Token([T_WHITESPACE, implode('', \array_slice($parts, 0, $expected)).rtrim($parts[$count - 1], "\r\n")]);
  81797. }
  81798. }
  81799. private function fixAfterToken(int $index): void
  81800. {
  81801. for ($i = $index - 1; $i > 0; --$i) {
  81802. if ($this->tokens[$i]->isGivenKind(T_FUNCTION) && $this->tokensAnalyzer->isLambda($i)) {
  81803. return;
  81804. }
  81805. if ($this->tokens[$i]->isGivenKind(T_CLASS) && $this->tokensAnalyzer->isAnonymousClass($i)) {
  81806. return;
  81807. }
  81808. if ($this->tokens[$i]->isGivenKind([CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN])) {
  81809. return;
  81810. }
  81811. if ($this->tokens[$i]->isWhitespace() && str_contains($this->tokens[$i]->getContent(), "\n")) {
  81812. break;
  81813. }
  81814. }
  81815. $this->removeEmptyLinesAfterLineWithTokenAt($index);
  81816. }
  81817. private function fixAfterCaseToken(int $index): void
  81818. {
  81819. $enumSwitchIndex = $this->tokens->getPrevTokenOfKind($index, [[T_SWITCH], [FCT::T_ENUM]]);
  81820. if (!$this->tokens[$enumSwitchIndex]->isGivenKind(T_SWITCH)) {
  81821. return;
  81822. }
  81823. $this->removeEmptyLinesAfterLineWithTokenAt($index);
  81824. }
  81825. private function fixAfterThrowToken(int $index): void
  81826. {
  81827. $prevIndex = $this->tokens->getPrevMeaningfulToken($index);
  81828. if (!$this->tokens[$prevIndex]->equalsAny([';', '{', '}', ':', [T_OPEN_TAG]])) {
  81829. return;
  81830. }
  81831. if ($this->tokens[$prevIndex]->equals(':') && !SwitchAnalyzer::belongsToSwitch($this->tokens, $prevIndex)) {
  81832. return;
  81833. }
  81834. $this->fixAfterToken($index);
  81835. }
  81836. private function fixStructureOpenCloseIfMultiLine(int $index): void
  81837. {
  81838. $blockTypeInfo = Tokens::detectBlockType($this->tokens[$index]);
  81839. $bodyEnd = $this->tokens->findBlockEnd($blockTypeInfo['type'], $index);
  81840. for ($i = $bodyEnd - 1; $i >= $index; --$i) {
  81841. if (str_contains($this->tokens[$i]->getContent(), "\n")) {
  81842. $this->removeEmptyLinesAfterLineWithTokenAt($i);
  81843. $this->removeEmptyLinesAfterLineWithTokenAt($index);
  81844. break;
  81845. }
  81846. }
  81847. }
  81848. private function removeEmptyLinesAfterLineWithTokenAt(int $index): void
  81849. {
  81850. $parenthesesDepth = 0;
  81851. $tokenCount = \count($this->tokens);
  81852. for ($end = $index; $end < $tokenCount; ++$end) {
  81853. if ($this->tokens[$end]->equals('(')) {
  81854. ++$parenthesesDepth;
  81855. continue;
  81856. }
  81857. if ($this->tokens[$end]->equals(')')) {
  81858. --$parenthesesDepth;
  81859. if ($parenthesesDepth < 0) {
  81860. return;
  81861. }
  81862. continue;
  81863. }
  81864. if (
  81865. $this->tokens[$end]->equals('}')
  81866. || str_contains($this->tokens[$end]->getContent(), "\n")
  81867. ) {
  81868. break;
  81869. }
  81870. }
  81871. if ($end === $tokenCount) {
  81872. return;
  81873. }
  81874. $ending = $this->whitespacesConfig->getLineEnding();
  81875. for ($i = $end; $i < $tokenCount && $this->tokens[$i]->isWhitespace(); ++$i) {
  81876. $content = $this->tokens[$i]->getContent();
  81877. if (substr_count($content, "\n") < 1) {
  81878. continue;
  81879. }
  81880. $newContent = Preg::replace('/^.*\R(\h*)$/s', $ending.'$1', $content);
  81881. $this->tokens[$i] = new Token([T_WHITESPACE, $newContent]);
  81882. }
  81883. }
  81884. private function containsLinebreak(int $startIndex, int $endIndex): bool
  81885. {
  81886. for ($i = $endIndex; $i > $startIndex; --$i) {
  81887. if (Preg::match('/\R/', $this->tokens[$i]->getContent())) {
  81888. return true;
  81889. }
  81890. }
  81891. return false;
  81892. }
  81893. }
  81894. <?php
  81895. declare(strict_types=1);
  81896. namespace PhpCsFixer\Fixer\Whitespace;
  81897. use PhpCsFixer\AbstractFixer;
  81898. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  81899. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  81900. use PhpCsFixer\Fixer\Indentation;
  81901. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  81902. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  81903. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  81904. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  81905. use PhpCsFixer\FixerDefinition\CodeSample;
  81906. use PhpCsFixer\FixerDefinition\FixerDefinition;
  81907. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  81908. use PhpCsFixer\Preg;
  81909. use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
  81910. use PhpCsFixer\Tokenizer\CT;
  81911. use PhpCsFixer\Tokenizer\FCT;
  81912. use PhpCsFixer\Tokenizer\Token;
  81913. use PhpCsFixer\Tokenizer\Tokens;
  81914. /**
  81915. @phpstan-type
  81916. @phpstan-type
  81917. @implements
  81918. */
  81919. final class StatementIndentationFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  81920. {
  81921. /**
  81922. @use */
  81923. use ConfigurableFixerTrait;
  81924. use Indentation;
  81925. private const BLOCK_SIGNATURE_FIRST_TOKENS = [
  81926. T_USE,
  81927. T_IF,
  81928. T_ELSE,
  81929. T_ELSEIF,
  81930. T_FOR,
  81931. T_FOREACH,
  81932. T_WHILE,
  81933. T_DO,
  81934. T_SWITCH,
  81935. T_CASE,
  81936. T_DEFAULT,
  81937. T_TRY,
  81938. T_CLASS,
  81939. T_INTERFACE,
  81940. T_TRAIT,
  81941. T_EXTENDS,
  81942. T_IMPLEMENTS,
  81943. T_CONST,
  81944. FCT::T_MATCH,
  81945. ];
  81946. private const CONTROL_STRUCTURE_POSSIBIBLY_WITHOUT_BRACES_TOKENS = [
  81947. T_IF,
  81948. T_ELSE,
  81949. T_ELSEIF,
  81950. T_FOR,
  81951. T_FOREACH,
  81952. T_WHILE,
  81953. T_DO,
  81954. ];
  81955. private const BLOCK_FIRST_TOKENS = ['{', [CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN], [CT::T_USE_TRAIT], [CT::T_GROUP_IMPORT_BRACE_OPEN], [CT::T_PROPERTY_HOOK_BRACE_OPEN], [FCT::T_ATTRIBUTE]];
  81956. private const PROPERTY_KEYWORDS = [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_STATIC, FCT::T_READONLY];
  81957. private AlternativeSyntaxAnalyzer $alternativeSyntaxAnalyzer;
  81958. private bool $bracesFixerCompatibility;
  81959. public function __construct(bool $bracesFixerCompatibility = false)
  81960. {
  81961. parent::__construct();
  81962. $this->bracesFixerCompatibility = $bracesFixerCompatibility;
  81963. }
  81964. public function getDefinition(): FixerDefinitionInterface
  81965. {
  81966. return new FixerDefinition(
  81967. 'Each statement must be indented.',
  81968. [
  81969. new CodeSample(
  81970. '<?php
  81971. if ($baz == true) {
  81972. echo "foo";
  81973. }
  81974. else {
  81975. echo "bar";
  81976. }
  81977. '
  81978. ),
  81979. new CodeSample(
  81980. '<?php
  81981. // foo
  81982. if ($foo) {
  81983. echo "foo";
  81984. // this is treated as comment of `if` block, as `stick_comment_to_next_continuous_control_statement` is disabled
  81985. } else {
  81986. $aaa = 1;
  81987. }
  81988. ',
  81989. ['stick_comment_to_next_continuous_control_statement' => false]
  81990. ),
  81991. new CodeSample(
  81992. '<?php
  81993. // foo
  81994. if ($foo) {
  81995. echo "foo";
  81996. // this is treated as comment of `elseif(1)` block, as `stick_comment_to_next_continuous_control_statement` is enabled
  81997. } elseif(1) {
  81998. echo "bar";
  81999. } elseif(2) {
  82000. // this is treated as comment of `elseif(2)` block, as the only content of that block
  82001. } elseif(3) {
  82002. $aaa = 1;
  82003. // this is treated as comment of `elseif(3)` block, as it is a comment in the final block
  82004. }
  82005. ',
  82006. ['stick_comment_to_next_continuous_control_statement' => true]
  82007. ),
  82008. ]
  82009. );
  82010. }
  82011. public function getPriority(): int
  82012. {
  82013. return -3;
  82014. }
  82015. public function isCandidate(Tokens $tokens): bool
  82016. {
  82017. return true;
  82018. }
  82019. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  82020. {
  82021. return new FixerConfigurationResolver([
  82022. (new FixerOptionBuilder('stick_comment_to_next_continuous_control_statement', 'Last comment of code block counts as comment for next block.'))
  82023. ->setAllowedTypes(['bool'])
  82024. ->setDefault(false)
  82025. ->getOption(),
  82026. ]);
  82027. }
  82028. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  82029. {
  82030. $this->alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
  82031. $endIndex = \count($tokens) - 1;
  82032. if ($tokens[$endIndex]->isWhitespace()) {
  82033. --$endIndex;
  82034. }
  82035. $lastIndent = $this->getLineIndentationWithBracesCompatibility(
  82036. $tokens,
  82037. 0,
  82038. $this->extractIndent($this->computeNewLineContent($tokens, 0)),
  82039. );
  82040. $scopes = [
  82041. [
  82042. 'type' => 'block',
  82043. 'skip' => false,
  82044. 'end_index' => $endIndex,
  82045. 'end_index_inclusive' => true,
  82046. 'initial_indent' => $lastIndent,
  82047. 'is_indented_block' => false,
  82048. ],
  82049. ];
  82050. $previousLineInitialIndent = '';
  82051. $previousLineNewIndent = '';
  82052. $noBracesBlockStarts = [];
  82053. $alternativeBlockStarts = [];
  82054. $caseBlockStarts = [];
  82055. foreach ($tokens as $index => $token) {
  82056. $currentScope = \count($scopes) - 1;
  82057. if (isset($noBracesBlockStarts[$index])) {
  82058. $scopes[] = [
  82059. 'type' => 'block',
  82060. 'skip' => false,
  82061. 'end_index' => $this->findStatementEndIndex($tokens, $index, \count($tokens) - 1) + 1,
  82062. 'end_index_inclusive' => true,
  82063. 'initial_indent' => $this->getLineIndentationWithBracesCompatibility($tokens, $index, $lastIndent),
  82064. 'is_indented_block' => true,
  82065. ];
  82066. ++$currentScope;
  82067. }
  82068. if (
  82069. $token->equalsAny(self::BLOCK_FIRST_TOKENS)
  82070. || ($token->equals('(') && !$tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_ARRAY))
  82071. || isset($alternativeBlockStarts[$index])
  82072. || isset($caseBlockStarts[$index])
  82073. ) {
  82074. $endIndexInclusive = true;
  82075. if ($token->isGivenKind([T_EXTENDS, T_IMPLEMENTS])) {
  82076. $endIndex = $tokens->getNextTokenOfKind($index, ['{']);
  82077. } elseif ($token->isGivenKind(CT::T_USE_TRAIT)) {
  82078. $endIndex = $tokens->getNextTokenOfKind($index, [';']);
  82079. } elseif ($token->equals(':')) {
  82080. if (isset($caseBlockStarts[$index])) {
  82081. [$endIndex, $endIndexInclusive] = $this->findCaseBlockEnd($tokens, $index);
  82082. } elseif ($this->alternativeSyntaxAnalyzer->belongsToAlternativeSyntax($tokens, $index)) {
  82083. $endIndex = $this->alternativeSyntaxAnalyzer->findAlternativeSyntaxBlockEnd($tokens, $alternativeBlockStarts[$index]);
  82084. }
  82085. } elseif ($token->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
  82086. $endIndex = $tokens->getNextTokenOfKind($index, [[CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]]);
  82087. } elseif ($token->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  82088. $endIndex = $tokens->getNextTokenOfKind($index, [[CT::T_GROUP_IMPORT_BRACE_CLOSE]]);
  82089. } elseif ($token->equals('{')) {
  82090. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  82091. } elseif ($token->equals('(')) {
  82092. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  82093. } elseif ($token->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
  82094. $endIndex = $tokens->getNextTokenOfKind($index, [[CT::T_PROPERTY_HOOK_BRACE_CLOSE]]);
  82095. } else {
  82096. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  82097. }
  82098. if ('block_signature' === $scopes[$currentScope]['type']) {
  82099. $initialIndent = $scopes[$currentScope]['initial_indent'];
  82100. } else {
  82101. $initialIndent = $this->getLineIndentationWithBracesCompatibility($tokens, $index, $lastIndent);
  82102. }
  82103. $skip = false;
  82104. if ($this->bracesFixerCompatibility) {
  82105. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  82106. if (null !== $prevIndex) {
  82107. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  82108. }
  82109. if (null !== $prevIndex && $tokens[$prevIndex]->isGivenKind([T_FUNCTION, T_FN])) {
  82110. $skip = true;
  82111. }
  82112. }
  82113. $scopes[] = [
  82114. 'type' => 'block',
  82115. 'skip' => $skip,
  82116. 'end_index' => $endIndex,
  82117. 'end_index_inclusive' => $endIndexInclusive,
  82118. 'initial_indent' => $initialIndent,
  82119. 'is_indented_block' => true,
  82120. ];
  82121. ++$currentScope;
  82122. while ($index >= $scopes[$currentScope]['end_index']) {
  82123. array_pop($scopes);
  82124. --$currentScope;
  82125. }
  82126. continue;
  82127. }
  82128. if (
  82129. $token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)
  82130. || ($token->equals('(') && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_ARRAY))
  82131. ) {
  82132. $blockType = $token->equals('(') ? Tokens::BLOCK_TYPE_PARENTHESIS_BRACE : Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE;
  82133. $scopes[] = [
  82134. 'type' => 'statement',
  82135. 'skip' => true,
  82136. 'end_index' => $tokens->findBlockEnd($blockType, $index),
  82137. 'end_index_inclusive' => true,
  82138. 'initial_indent' => $previousLineInitialIndent,
  82139. 'new_indent' => $previousLineNewIndent,
  82140. 'is_indented_block' => false,
  82141. ];
  82142. continue;
  82143. }
  82144. $isPropertyStart = $this->isPropertyStart($tokens, $index);
  82145. if ($isPropertyStart || $token->isGivenKind(self::BLOCK_SIGNATURE_FIRST_TOKENS)) {
  82146. $lastWhitespaceIndex = null;
  82147. $closingParenthesisIndex = null;
  82148. for ($endIndex = $index + 1, $max = \count($tokens); $endIndex < $max; ++$endIndex) {
  82149. $endToken = $tokens[$endIndex];
  82150. if ($endToken->equals('(')) {
  82151. $closingParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex);
  82152. $endIndex = $closingParenthesisIndex;
  82153. continue;
  82154. }
  82155. if ($endToken->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  82156. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $endIndex);
  82157. continue;
  82158. }
  82159. if ($endToken->equalsAny(['{', ';', [T_DOUBLE_ARROW], [T_IMPLEMENTS]])) {
  82160. break;
  82161. }
  82162. if ($endToken->equals(':')) {
  82163. if ($token->isGivenKind([T_CASE, T_DEFAULT])) {
  82164. $caseBlockStarts[$endIndex] = $index;
  82165. } else {
  82166. $alternativeBlockStarts[$endIndex] = $index;
  82167. }
  82168. break;
  82169. }
  82170. if (!$token->isGivenKind(self::CONTROL_STRUCTURE_POSSIBIBLY_WITHOUT_BRACES_TOKENS)) {
  82171. continue;
  82172. }
  82173. if ($endToken->isWhitespace()) {
  82174. $lastWhitespaceIndex = $endIndex;
  82175. continue;
  82176. }
  82177. if (!$endToken->isComment()) {
  82178. $noBraceBlockStartIndex = $lastWhitespaceIndex ?? $endIndex;
  82179. $noBracesBlockStarts[$noBraceBlockStartIndex] = true;
  82180. $endIndex = $closingParenthesisIndex ?? $index;
  82181. break;
  82182. }
  82183. }
  82184. $scopes[] = [
  82185. 'type' => 'block_signature',
  82186. 'skip' => false,
  82187. 'end_index' => $endIndex,
  82188. 'end_index_inclusive' => true,
  82189. 'initial_indent' => $this->getLineIndentationWithBracesCompatibility($tokens, $index, $lastIndent),
  82190. 'is_indented_block' => $isPropertyStart || $token->isGivenKind([T_EXTENDS, T_IMPLEMENTS, T_CONST]),
  82191. ];
  82192. continue;
  82193. }
  82194. if ($token->isGivenKind(T_FUNCTION)) {
  82195. $endIndex = $index + 1;
  82196. for ($max = \count($tokens); $endIndex < $max; ++$endIndex) {
  82197. if ($tokens[$endIndex]->equals('(')) {
  82198. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex);
  82199. continue;
  82200. }
  82201. if ($tokens[$endIndex]->equalsAny(['{', ';'])) {
  82202. break;
  82203. }
  82204. }
  82205. $scopes[] = [
  82206. 'type' => 'block_signature',
  82207. 'skip' => false,
  82208. 'end_index' => $endIndex,
  82209. 'end_index_inclusive' => true,
  82210. 'initial_indent' => $this->getLineIndentationWithBracesCompatibility($tokens, $index, $lastIndent),
  82211. 'is_indented_block' => false,
  82212. ];
  82213. continue;
  82214. }
  82215. if (
  82216. $token->isWhitespace()
  82217. || ($index > 0 && $tokens[$index - 1]->isGivenKind(T_OPEN_TAG))
  82218. ) {
  82219. $previousOpenTagContent = $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)
  82220. ? Preg::replace('/\S/', '', $tokens[$index - 1]->getContent())
  82221. : '';
  82222. $content = $previousOpenTagContent.($token->isWhitespace() ? $token->getContent() : '');
  82223. if (!Preg::match('/\R/', $content)) {
  82224. continue;
  82225. }
  82226. $nextToken = $tokens[$index + 1] ?? null;
  82227. if (
  82228. $this->bracesFixerCompatibility
  82229. && null !== $nextToken
  82230. && $nextToken->isComment()
  82231. && !$this->isCommentWithFixableIndentation($tokens, $index + 1)
  82232. ) {
  82233. continue;
  82234. }
  82235. if ('block' === $scopes[$currentScope]['type'] || 'block_signature' === $scopes[$currentScope]['type']) {
  82236. $indent = false;
  82237. if ($scopes[$currentScope]['is_indented_block']) {
  82238. $firstNonWhitespaceTokenIndex = null;
  82239. $nextNewlineIndex = null;
  82240. for ($searchIndex = $index + 1, $max = \count($tokens); $searchIndex < $max; ++$searchIndex) {
  82241. $searchToken = $tokens[$searchIndex];
  82242. if (!$searchToken->isWhitespace()) {
  82243. if (null === $firstNonWhitespaceTokenIndex) {
  82244. $firstNonWhitespaceTokenIndex = $searchIndex;
  82245. }
  82246. continue;
  82247. }
  82248. if (Preg::match('/\R/', $searchToken->getContent())) {
  82249. $nextNewlineIndex = $searchIndex;
  82250. break;
  82251. }
  82252. }
  82253. $endIndex = $scopes[$currentScope]['end_index'];
  82254. if (!$scopes[$currentScope]['end_index_inclusive']) {
  82255. ++$endIndex;
  82256. }
  82257. if (
  82258. (null !== $firstNonWhitespaceTokenIndex && $firstNonWhitespaceTokenIndex < $endIndex)
  82259. || (null !== $nextNewlineIndex && $nextNewlineIndex < $endIndex)
  82260. ) {
  82261. if (
  82262. $tokens[$firstNonWhitespaceTokenIndex]->isGivenKind(T_COMMENT)
  82263. && $tokens[$tokens->getNextMeaningfulToken($firstNonWhitespaceTokenIndex)]->equals('}')
  82264. ) {
  82265. if (
  82266. $tokens[$tokens->getPrevMeaningfulToken($firstNonWhitespaceTokenIndex)]->equals('{')
  82267. ) {
  82268. $indent = true;
  82269. } else {
  82270. $nextIndex = $tokens->getNextMeaningfulToken($firstNonWhitespaceTokenIndex);
  82271. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  82272. if (null !== $nextNextIndex && $tokens[$nextNextIndex]->isGivenKind([T_ELSE, T_ELSEIF])) {
  82273. $indent = true !== $this->configuration['stick_comment_to_next_continuous_control_statement'];
  82274. } else {
  82275. $indent = true;
  82276. }
  82277. }
  82278. } else {
  82279. $indent = true;
  82280. }
  82281. }
  82282. }
  82283. $previousLineInitialIndent = $this->extractIndent($content);
  82284. if ($scopes[$currentScope]['skip']) {
  82285. $whitespaces = $previousLineInitialIndent;
  82286. } else {
  82287. $whitespaces = $scopes[$currentScope]['initial_indent'].($indent ? $this->whitespacesConfig->getIndent() : '');
  82288. }
  82289. $content = Preg::replace(
  82290. '/(\R+)\h*$/',
  82291. '$1'.$whitespaces,
  82292. $content
  82293. );
  82294. $previousLineNewIndent = $this->extractIndent($content);
  82295. } else {
  82296. $content = Preg::replace(
  82297. '/(\R)'.$scopes[$currentScope]['initial_indent'].'(\h*)$/D',
  82298. '$1'.$scopes[$currentScope]['new_indent'].'$2',
  82299. $content
  82300. );
  82301. }
  82302. $lastIndent = $this->extractIndent($content);
  82303. if ('' !== $previousOpenTagContent) {
  82304. $content = Preg::replace("/^{$previousOpenTagContent}/", '', $content);
  82305. }
  82306. if ('' !== $content) {
  82307. $tokens->ensureWhitespaceAtIndex($index, 0, $content);
  82308. } elseif ($token->isWhitespace()) {
  82309. $tokens->clearAt($index);
  82310. }
  82311. if (null !== $nextToken && $nextToken->isComment()) {
  82312. $tokens[$index + 1] = new Token([
  82313. $nextToken->getId(),
  82314. Preg::replace(
  82315. '/(\R)'.preg_quote($previousLineInitialIndent, '/').'(\h*\S+.*)/',
  82316. '$1'.$previousLineNewIndent.'$2',
  82317. $nextToken->getContent()
  82318. ),
  82319. ]);
  82320. }
  82321. if ($token->isWhitespace()) {
  82322. continue;
  82323. }
  82324. }
  82325. if ($this->isNewLineToken($tokens, $index)) {
  82326. $lastIndent = $this->extractIndent($this->computeNewLineContent($tokens, $index));
  82327. }
  82328. while ($index >= $scopes[$currentScope]['end_index']) {
  82329. array_pop($scopes);
  82330. if ([] === $scopes) {
  82331. return;
  82332. }
  82333. --$currentScope;
  82334. }
  82335. if ($token->isComment() || $token->equalsAny([';', ',', '}', [T_OPEN_TAG], [T_CLOSE_TAG], [CT::T_ATTRIBUTE_CLOSE]])) {
  82336. continue;
  82337. }
  82338. if ('statement' !== $scopes[$currentScope]['type'] && 'block_signature' !== $scopes[$currentScope]['type']) {
  82339. $endIndex = $this->findStatementEndIndex($tokens, $index, $scopes[$currentScope]['end_index']);
  82340. if ($endIndex === $index) {
  82341. continue;
  82342. }
  82343. $scopes[] = [
  82344. 'type' => 'statement',
  82345. 'skip' => false,
  82346. 'end_index' => $endIndex,
  82347. 'end_index_inclusive' => false,
  82348. 'initial_indent' => $previousLineInitialIndent,
  82349. 'new_indent' => $previousLineNewIndent,
  82350. 'is_indented_block' => true,
  82351. ];
  82352. }
  82353. }
  82354. }
  82355. private function findStatementEndIndex(Tokens $tokens, int $index, int $parentScopeEndIndex): int
  82356. {
  82357. $endIndex = null;
  82358. $ifLevel = 0;
  82359. $doWhileLevel = 0;
  82360. for ($searchEndIndex = $index; $searchEndIndex <= $parentScopeEndIndex; ++$searchEndIndex) {
  82361. $searchEndToken = $tokens[$searchEndIndex];
  82362. if (
  82363. $searchEndToken->isGivenKind(T_IF)
  82364. && !$tokens[$tokens->getPrevMeaningfulToken($searchEndIndex)]->isGivenKind(T_ELSE)
  82365. ) {
  82366. ++$ifLevel;
  82367. continue;
  82368. }
  82369. if ($searchEndToken->isGivenKind(T_DO)) {
  82370. ++$doWhileLevel;
  82371. continue;
  82372. }
  82373. if ($searchEndToken->equalsAny(['(', '{', [CT::T_ARRAY_SQUARE_BRACE_OPEN]])) {
  82374. if ($searchEndToken->equals('(')) {
  82375. $blockType = Tokens::BLOCK_TYPE_PARENTHESIS_BRACE;
  82376. } elseif ($searchEndToken->equals('{')) {
  82377. $blockType = Tokens::BLOCK_TYPE_CURLY_BRACE;
  82378. } else {
  82379. $blockType = Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE;
  82380. }
  82381. $searchEndIndex = $tokens->findBlockEnd($blockType, $searchEndIndex);
  82382. $searchEndToken = $tokens[$searchEndIndex];
  82383. }
  82384. if (!$searchEndToken->equalsAny([';', ',', '}', [T_CLOSE_TAG]])) {
  82385. continue;
  82386. }
  82387. $controlStructureContinuationIndex = $tokens->getNextMeaningfulToken($searchEndIndex);
  82388. if (
  82389. $ifLevel > 0
  82390. && null !== $controlStructureContinuationIndex
  82391. && $tokens[$controlStructureContinuationIndex]->isGivenKind([T_ELSE, T_ELSEIF])
  82392. ) {
  82393. if (
  82394. $tokens[$controlStructureContinuationIndex]->isGivenKind(T_ELSE)
  82395. && !$tokens[$tokens->getNextMeaningfulToken($controlStructureContinuationIndex)]->isGivenKind(T_IF)
  82396. ) {
  82397. --$ifLevel;
  82398. }
  82399. $searchEndIndex = $controlStructureContinuationIndex;
  82400. continue;
  82401. }
  82402. if (
  82403. $doWhileLevel > 0
  82404. && null !== $controlStructureContinuationIndex
  82405. && $tokens[$controlStructureContinuationIndex]->isGivenKind([T_WHILE])
  82406. ) {
  82407. --$doWhileLevel;
  82408. $searchEndIndex = $controlStructureContinuationIndex;
  82409. continue;
  82410. }
  82411. $endIndex = $tokens->getPrevNonWhitespace($searchEndIndex);
  82412. break;
  82413. }
  82414. return $endIndex ?? $tokens->getPrevMeaningfulToken($parentScopeEndIndex);
  82415. }
  82416. private function findCaseBlockEnd(Tokens $tokens, int $index): array
  82417. {
  82418. for ($max = \count($tokens); $index < $max; ++$index) {
  82419. if ($tokens[$index]->isGivenKind(T_SWITCH)) {
  82420. $braceIndex = $tokens->getNextMeaningfulToken(
  82421. $tokens->findBlockEnd(
  82422. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  82423. $tokens->getNextMeaningfulToken($index)
  82424. )
  82425. );
  82426. if ($tokens[$braceIndex]->equals(':')) {
  82427. $index = $this->alternativeSyntaxAnalyzer->findAlternativeSyntaxBlockEnd($tokens, $index);
  82428. } else {
  82429. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $braceIndex);
  82430. }
  82431. continue;
  82432. }
  82433. if ($tokens[$index]->equals('{')) {
  82434. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  82435. continue;
  82436. }
  82437. if ($tokens[$index]->equalsAny([[T_CASE], [T_DEFAULT]])) {
  82438. return [$index, true];
  82439. }
  82440. if ($tokens[$index]->equalsAny(['}', [T_ENDSWITCH]])) {
  82441. return [$tokens->getPrevNonWhitespace($index), false];
  82442. }
  82443. }
  82444. throw new \LogicException('End of case block not found.');
  82445. }
  82446. private function getLineIndentationWithBracesCompatibility(Tokens $tokens, int $index, string $regularIndent): string
  82447. {
  82448. if (
  82449. $this->bracesFixerCompatibility
  82450. && $tokens[$index]->isGivenKind(T_OPEN_TAG)
  82451. && Preg::match('/\R/', $tokens[$index]->getContent())
  82452. && isset($tokens[$index + 1])
  82453. && $tokens[$index + 1]->isWhitespace()
  82454. && Preg::match('/\h+$/D', $tokens[$index + 1]->getContent())
  82455. ) {
  82456. return Preg::replace('/.*?(\h+)$/sD', '$1', $tokens[$index + 1]->getContent());
  82457. }
  82458. return $regularIndent;
  82459. }
  82460. private function isPropertyStart(Tokens $tokens, int $index): bool
  82461. {
  82462. $nextIndex = $tokens->getNextMeaningfulToken($index);
  82463. if (
  82464. null === $nextIndex
  82465. || $tokens[$nextIndex]->isGivenKind(self::PROPERTY_KEYWORDS)
  82466. || $tokens[$nextIndex]->isGivenKind([T_CONST, T_FUNCTION])
  82467. ) {
  82468. return false;
  82469. }
  82470. while ($tokens[$index]->isGivenKind(self::PROPERTY_KEYWORDS)) {
  82471. if ($tokens[$index]->isGivenKind([T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE])) {
  82472. return true;
  82473. }
  82474. $index = $tokens->getPrevMeaningfulToken($index);
  82475. }
  82476. return false;
  82477. }
  82478. private function isCommentWithFixableIndentation(Tokens $tokens, int $index): bool
  82479. {
  82480. if (!$tokens[$index]->isComment()) {
  82481. return false;
  82482. }
  82483. if (str_starts_with($tokens[$index]->getContent(), '/*')) {
  82484. return true;
  82485. }
  82486. $indent = preg_quote($this->whitespacesConfig->getIndent(), '~');
  82487. if (Preg::match("~^(//|#)({$indent}.*)?$~", $tokens[$index]->getContent())) {
  82488. return false;
  82489. }
  82490. $firstCommentIndex = $index;
  82491. while (true) {
  82492. $firstCommentCandidateIndex = $this->getSiblingContinuousSingleLineComment($tokens, $firstCommentIndex, false);
  82493. if (null === $firstCommentCandidateIndex) {
  82494. break;
  82495. }
  82496. $firstCommentIndex = $firstCommentCandidateIndex;
  82497. }
  82498. $lastCommentIndex = $index;
  82499. while (true) {
  82500. $lastCommentCandidateIndex = $this->getSiblingContinuousSingleLineComment($tokens, $lastCommentIndex, true);
  82501. if (null === $lastCommentCandidateIndex) {
  82502. break;
  82503. }
  82504. $lastCommentIndex = $lastCommentCandidateIndex;
  82505. }
  82506. if ($firstCommentIndex === $lastCommentIndex) {
  82507. return true;
  82508. }
  82509. for ($i = $firstCommentIndex + 1; $i < $lastCommentIndex; ++$i) {
  82510. if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isComment()) {
  82511. return false;
  82512. }
  82513. }
  82514. return true;
  82515. }
  82516. private function getSiblingContinuousSingleLineComment(Tokens $tokens, int $index, bool $after): ?int
  82517. {
  82518. $siblingIndex = $index;
  82519. do {
  82520. if ($after) {
  82521. $siblingIndex = $tokens->getNextTokenOfKind($siblingIndex, [[T_COMMENT]]);
  82522. } else {
  82523. $siblingIndex = $tokens->getPrevTokenOfKind($siblingIndex, [[T_COMMENT]]);
  82524. }
  82525. if (null === $siblingIndex) {
  82526. return null;
  82527. }
  82528. } while (str_starts_with($tokens[$siblingIndex]->getContent(), '/*'));
  82529. $newLines = 0;
  82530. for ($i = min($siblingIndex, $index) + 1, $max = max($siblingIndex, $index); $i < $max; ++$i) {
  82531. if ($tokens[$i]->isWhitespace() && Preg::match('/\R/', $tokens[$i]->getContent())) {
  82532. if (1 === $newLines || Preg::match('/\R.*\R/', $tokens[$i]->getContent())) {
  82533. return null;
  82534. }
  82535. ++$newLines;
  82536. }
  82537. }
  82538. return $siblingIndex;
  82539. }
  82540. }
  82541. <?php
  82542. declare(strict_types=1);
  82543. namespace PhpCsFixer\Fixer\Naming;
  82544. use PhpCsFixer\AbstractFixer;
  82545. use PhpCsFixer\FixerDefinition\CodeSample;
  82546. use PhpCsFixer\FixerDefinition\FixerDefinition;
  82547. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  82548. use PhpCsFixer\Preg;
  82549. use PhpCsFixer\Tokenizer\Token;
  82550. use PhpCsFixer\Tokenizer\Tokens;
  82551. final class NoHomoglyphNamesFixer extends AbstractFixer
  82552. {
  82553. private const REPLACEMENTS = [
  82554. 'O' => '0',
  82555. '�' => '0',
  82556. 'I' => '1',
  82557. '1' => '1',
  82558. 'ï¼’' => '2',
  82559. '3' => '3',
  82560. 'ï¼”' => '4',
  82561. '5' => '5',
  82562. 'ï¼–' => '6',
  82563. 'ï¼—' => '7',
  82564. '8' => '8',
  82565. 'ï¼™' => '9',
  82566. 'Α' => 'A',
  82567. '�' => 'A',
  82568. 'A' => 'A',
  82569. 'Ê™' => 'B',
  82570. 'Î’' => 'B',
  82571. 'Ð’' => 'B',
  82572. 'ï¼¢' => 'B',
  82573. 'Ϲ' => 'C',
  82574. 'С' => 'C',
  82575. 'â…­' => 'C',
  82576. 'ï¼£' => 'C',
  82577. 'â…®' => 'D',
  82578. 'D' => 'D',
  82579. 'Ε' => 'E',
  82580. 'Е' => 'E',
  82581. 'ï¼¥' => 'E',
  82582. 'Ϝ' => 'F',
  82583. 'F' => 'F',
  82584. 'É¢' => 'G',
  82585. 'Ԍ' => 'G',
  82586. 'ï¼§' => 'G',
  82587. 'ʜ' => 'H',
  82588. 'Η' => 'H',
  82589. '�' => 'H',
  82590. 'H' => 'H',
  82591. 'l' => 'I',
  82592. 'Ι' => 'I',
  82593. 'І' => 'I',
  82594. 'â… ' => 'I',
  82595. 'I' => 'I',
  82596. 'Ј' => 'J',
  82597. 'J' => 'J',
  82598. 'Κ' => 'K',
  82599. 'К' => 'K',
  82600. 'K' => 'K',
  82601. 'K' => 'K',
  82602. 'ÊŸ' => 'L',
  82603. 'â…¬' => 'L',
  82604. 'L' => 'L',
  82605. 'Μ' => 'M',
  82606. 'М' => 'M',
  82607. 'â…¯' => 'M',
  82608. 'ï¼­' => 'M',
  82609. 'É´' => 'N',
  82610. '�' => 'N',
  82611. 'ï¼®' => 'N',
  82612. 'Ο' => 'O',
  82613. 'О' => 'O',
  82614. 'O' => 'O',
  82615. 'Ρ' => 'P',
  82616. 'Р' => 'P',
  82617. 'ï¼°' => 'P',
  82618. 'ï¼±' => 'Q',
  82619. 'Ê€' => 'R',
  82620. 'ï¼²' => 'R',
  82621. 'Ð…' => 'S',
  82622. 'ï¼³' => 'S',
  82623. 'Τ' => 'T',
  82624. 'Т' => 'T',
  82625. 'ï¼´' => 'T',
  82626. 'ï¼µ' => 'U',
  82627. 'Ñ´' => 'V',
  82628. 'â…¤' => 'V',
  82629. 'ï¼¶' => 'V',
  82630. 'ï¼·' => 'W',
  82631. 'Χ' => 'X',
  82632. 'Ð¥' => 'X',
  82633. 'â…©' => 'X',
  82634. 'X' => 'X',
  82635. '�' => 'Y',
  82636. 'Î¥' => 'Y',
  82637. 'Ò®' => 'Y',
  82638. 'ï¼¹' => 'Y',
  82639. 'Ζ' => 'Z',
  82640. 'Z' => 'Z',
  82641. '_' => '_',
  82642. 'É‘' => 'a',
  82643. 'а' => 'a',
  82644. '�' => 'a',
  82645. 'Ь' => 'b',
  82646. 'b' => 'b',
  82647. 'ϲ' => 'c',
  82648. '�' => 'c',
  82649. 'â…½' => 'c',
  82650. 'c' => 'c',
  82651. 'Ô�' => 'd',
  82652. 'â…¾' => 'd',
  82653. 'd' => 'd',
  82654. 'е' => 'e',
  82655. 'ï½…' => 'e',
  82656. 'f' => 'f',
  82657. 'É¡' => 'g',
  82658. 'g' => 'g',
  82659. 'Ò»' => 'h',
  82660. 'h' => 'h',
  82661. 'É©' => 'i',
  82662. 'Ñ–' => 'i',
  82663. 'â…°' => 'i',
  82664. 'i' => 'i',
  82665. 'ј' => 'j',
  82666. 'j' => 'j',
  82667. 'k' => 'k',
  82668. 'â…¼' => 'l',
  82669. 'l' => 'l',
  82670. 'â…¿' => 'm',
  82671. '�' => 'm',
  82672. 'n' => 'n',
  82673. 'ο' => 'o',
  82674. 'о' => 'o',
  82675. '�' => 'o',
  82676. 'Ñ€' => 'p',
  82677. '�' => 'p',
  82678. 'q' => 'q',
  82679. 'ï½’' => 'r',
  82680. 'Ñ•' => 's',
  82681. 's' => 's',
  82682. 'ï½”' => 't',
  82683. 'u' => 'u',
  82684. 'ν' => 'v',
  82685. 'ѵ' => 'v',
  82686. 'â…´' => 'v',
  82687. 'ï½–' => 'v',
  82688. 'Ñ¡' => 'w',
  82689. 'ï½—' => 'w',
  82690. 'Ñ…' => 'x',
  82691. 'â…¹' => 'x',
  82692. 'x' => 'x',
  82693. 'у' => 'y',
  82694. 'ï½™' => 'y',
  82695. 'z' => 'z',
  82696. ];
  82697. public function getDefinition(): FixerDefinitionInterface
  82698. {
  82699. return new FixerDefinition(
  82700. 'Replace accidental usage of homoglyphs (non ascii characters) in names.',
  82701. [new CodeSample("<?php \$nаmе = 'wrong \"a\" character';\n")],
  82702. null,
  82703. 'Renames classes and cannot rename the files. You might have string references to renamed code (`$$name`).'
  82704. );
  82705. }
  82706. public function isRisky(): bool
  82707. {
  82708. return true;
  82709. }
  82710. public function isCandidate(Tokens $tokens): bool
  82711. {
  82712. return $tokens->isAnyTokenKindsFound([T_VARIABLE, T_STRING]);
  82713. }
  82714. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  82715. {
  82716. foreach ($tokens as $index => $token) {
  82717. if (!$token->isGivenKind([T_VARIABLE, T_STRING])) {
  82718. continue;
  82719. }
  82720. $replaced = Preg::replaceCallback('/[^[:ascii:]]/u', static fn (array $matches): string => self::REPLACEMENTS[$matches[0]] ?? $matches[0], $token->getContent(), -1, $count);
  82721. if ($count > 0) {
  82722. $tokens->offsetSet($index, new Token([$token->getId(), $replaced]));
  82723. }
  82724. }
  82725. }
  82726. }
  82727. <?php
  82728. declare(strict_types=1);
  82729. namespace PhpCsFixer\Fixer\Strict;
  82730. use PhpCsFixer\AbstractFixer;
  82731. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  82732. use PhpCsFixer\FixerDefinition\CodeSample;
  82733. use PhpCsFixer\FixerDefinition\FixerDefinition;
  82734. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  82735. use PhpCsFixer\Tokenizer\Token;
  82736. use PhpCsFixer\Tokenizer\Tokens;
  82737. final class DeclareStrictTypesFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  82738. {
  82739. public function getDefinition(): FixerDefinitionInterface
  82740. {
  82741. return new FixerDefinition(
  82742. 'Force strict types declaration in all files.',
  82743. [
  82744. new CodeSample(
  82745. "<?php\n"
  82746. ),
  82747. ],
  82748. null,
  82749. 'Forcing strict types will stop non strict code from working.'
  82750. );
  82751. }
  82752. public function getPriority(): int
  82753. {
  82754. return 2;
  82755. }
  82756. public function isCandidate(Tokens $tokens): bool
  82757. {
  82758. return $tokens->isMonolithicPhp() && !$tokens->isTokenKindFound(T_OPEN_TAG_WITH_ECHO);
  82759. }
  82760. public function isRisky(): bool
  82761. {
  82762. return true;
  82763. }
  82764. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  82765. {
  82766. $openTagIndex = $tokens[0]->isGivenKind(T_INLINE_HTML) ? 1 : 0;
  82767. $sequenceLocation = $tokens->findSequence([[T_DECLARE, 'declare'], '(', [T_STRING, 'strict_types'], '=', [T_LNUMBER], ')'], $openTagIndex, null, false);
  82768. if (null === $sequenceLocation) {
  82769. $this->insertSequence($openTagIndex, $tokens);
  82770. return;
  82771. }
  82772. $this->fixStrictTypesCasingAndValue($tokens, $sequenceLocation);
  82773. }
  82774. private function fixStrictTypesCasingAndValue(Tokens $tokens, array $sequence): void
  82775. {
  82776. foreach ($sequence as $index => $token) {
  82777. if ($token->isGivenKind(T_STRING)) {
  82778. $tokens[$index] = new Token([T_STRING, strtolower($token->getContent())]);
  82779. continue;
  82780. }
  82781. if ($token->isGivenKind(T_LNUMBER)) {
  82782. $tokens[$index] = new Token([T_LNUMBER, '1']);
  82783. break;
  82784. }
  82785. }
  82786. }
  82787. private function insertSequence(int $openTagIndex, Tokens $tokens): void
  82788. {
  82789. $sequence = [
  82790. new Token([T_DECLARE, 'declare']),
  82791. new Token('('),
  82792. new Token([T_STRING, 'strict_types']),
  82793. new Token('='),
  82794. new Token([T_LNUMBER, '1']),
  82795. new Token(')'),
  82796. new Token(';'),
  82797. ];
  82798. $nextIndex = $openTagIndex + \count($sequence) + 1;
  82799. $tokens->insertAt($openTagIndex + 1, $sequence);
  82800. $content = $tokens[$openTagIndex]->getContent();
  82801. if (!str_contains($content, ' ') || str_contains($content, "\n")) {
  82802. $tokens[$openTagIndex] = new Token([$tokens[$openTagIndex]->getId(), trim($tokens[$openTagIndex]->getContent()).' ']);
  82803. }
  82804. if (\count($tokens) === $nextIndex) {
  82805. return;
  82806. }
  82807. $lineEnding = $this->whitespacesConfig->getLineEnding();
  82808. if ($tokens[$nextIndex]->isWhitespace()) {
  82809. $content = $tokens[$nextIndex]->getContent();
  82810. $tokens[$nextIndex] = new Token([T_WHITESPACE, $lineEnding.ltrim($content, " \t")]);
  82811. } else {
  82812. $tokens->insertAt($nextIndex, new Token([T_WHITESPACE, $lineEnding]));
  82813. }
  82814. }
  82815. }
  82816. <?php
  82817. declare(strict_types=1);
  82818. namespace PhpCsFixer\Fixer\Strict;
  82819. use PhpCsFixer\AbstractFixer;
  82820. use PhpCsFixer\FixerDefinition\CodeSample;
  82821. use PhpCsFixer\FixerDefinition\FixerDefinition;
  82822. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  82823. use PhpCsFixer\Tokenizer\Token;
  82824. use PhpCsFixer\Tokenizer\Tokens;
  82825. final class StrictComparisonFixer extends AbstractFixer
  82826. {
  82827. public function getDefinition(): FixerDefinitionInterface
  82828. {
  82829. return new FixerDefinition(
  82830. 'Comparisons should be strict.',
  82831. [new CodeSample("<?php\n\$a = 1== \$b;\n")],
  82832. null,
  82833. 'Changing comparisons to strict might change code behavior.'
  82834. );
  82835. }
  82836. public function getPriority(): int
  82837. {
  82838. return 38;
  82839. }
  82840. public function isCandidate(Tokens $tokens): bool
  82841. {
  82842. return $tokens->isAnyTokenKindsFound([T_IS_EQUAL, T_IS_NOT_EQUAL]);
  82843. }
  82844. public function isRisky(): bool
  82845. {
  82846. return true;
  82847. }
  82848. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  82849. {
  82850. static $map = [
  82851. T_IS_EQUAL => [
  82852. 'id' => T_IS_IDENTICAL,
  82853. 'content' => '===',
  82854. ],
  82855. T_IS_NOT_EQUAL => [
  82856. 'id' => T_IS_NOT_IDENTICAL,
  82857. 'content' => '!==',
  82858. ],
  82859. ];
  82860. foreach ($tokens as $index => $token) {
  82861. $tokenId = $token->getId();
  82862. if (isset($map[$tokenId])) {
  82863. $tokens[$index] = new Token([$map[$tokenId]['id'], $map[$tokenId]['content']]);
  82864. }
  82865. }
  82866. }
  82867. }
  82868. <?php
  82869. declare(strict_types=1);
  82870. namespace PhpCsFixer\Fixer\Strict;
  82871. use PhpCsFixer\AbstractFixer;
  82872. use PhpCsFixer\FixerDefinition\CodeSample;
  82873. use PhpCsFixer\FixerDefinition\FixerDefinition;
  82874. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  82875. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  82876. use PhpCsFixer\Tokenizer\CT;
  82877. use PhpCsFixer\Tokenizer\Token;
  82878. use PhpCsFixer\Tokenizer\Tokens;
  82879. final class StrictParamFixer extends AbstractFixer
  82880. {
  82881. public function getDefinition(): FixerDefinitionInterface
  82882. {
  82883. return new FixerDefinition(
  82884. 'Functions should be used with `$strict` param set to `true`.',
  82885. [new CodeSample("<?php\n\$a = array_keys(\$b);\n\$a = array_search(\$b, \$c);\n\$a = base64_decode(\$b);\n\$a = in_array(\$b, \$c);\n\$a = mb_detect_encoding(\$b, \$c);\n")],
  82886. 'The functions "array_keys", "array_search", "base64_decode", "in_array" and "mb_detect_encoding" should be used with $strict param.',
  82887. 'Risky when the fixed function is overridden or if the code relies on non-strict usage.'
  82888. );
  82889. }
  82890. public function isCandidate(Tokens $tokens): bool
  82891. {
  82892. return $tokens->isTokenKindFound(T_STRING);
  82893. }
  82894. public function isRisky(): bool
  82895. {
  82896. return true;
  82897. }
  82898. public function getPriority(): int
  82899. {
  82900. return 31;
  82901. }
  82902. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  82903. {
  82904. $functionsAnalyzer = new FunctionsAnalyzer();
  82905. static $map = null;
  82906. if (null === $map) {
  82907. $trueToken = new Token([T_STRING, 'true']);
  82908. $map = [
  82909. 'array_keys' => [null, null, $trueToken],
  82910. 'array_search' => [null, null, $trueToken],
  82911. 'base64_decode' => [null, $trueToken],
  82912. 'in_array' => [null, null, $trueToken],
  82913. 'mb_detect_encoding' => [null, [new Token([T_STRING, 'mb_detect_order']), new Token('('), new Token(')')], $trueToken],
  82914. ];
  82915. }
  82916. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  82917. $token = $tokens[$index];
  82918. $nextIndex = $tokens->getNextMeaningfulToken($index);
  82919. if (null !== $nextIndex && !$tokens[$nextIndex]->equals('(')) {
  82920. continue;
  82921. }
  82922. $lowercaseContent = strtolower($token->getContent());
  82923. if (isset($map[$lowercaseContent]) && $functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
  82924. $this->fixFunction($tokens, $index, $map[$lowercaseContent]);
  82925. }
  82926. }
  82927. }
  82928. private function fixFunction(Tokens $tokens, int $functionIndex, array $functionParams): void
  82929. {
  82930. $startBraceIndex = $tokens->getNextTokenOfKind($functionIndex, ['(']);
  82931. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startBraceIndex);
  82932. $paramsQuantity = 0;
  82933. $expectParam = true;
  82934. for ($index = $startBraceIndex + 1; $index < $endBraceIndex; ++$index) {
  82935. $token = $tokens[$index];
  82936. if ($expectParam && !$token->isWhitespace() && !$token->isComment()) {
  82937. ++$paramsQuantity;
  82938. $expectParam = false;
  82939. }
  82940. if ($token->equals('(')) {
  82941. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  82942. continue;
  82943. }
  82944. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  82945. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  82946. continue;
  82947. }
  82948. if ($token->equals(',')) {
  82949. $expectParam = true;
  82950. continue;
  82951. }
  82952. }
  82953. $functionParamsQuantity = \count($functionParams);
  82954. if ($paramsQuantity === $functionParamsQuantity) {
  82955. return;
  82956. }
  82957. $tokensToInsert = [];
  82958. for ($i = $paramsQuantity; $i < $functionParamsQuantity; ++$i) {
  82959. if (null === $functionParams[$i]) {
  82960. return;
  82961. }
  82962. $tokensToInsert[] = new Token(',');
  82963. $tokensToInsert[] = new Token([T_WHITESPACE, ' ']);
  82964. if (!\is_array($functionParams[$i])) {
  82965. $tokensToInsert[] = clone $functionParams[$i];
  82966. continue;
  82967. }
  82968. foreach ($functionParams[$i] as $param) {
  82969. $tokensToInsert[] = clone $param;
  82970. }
  82971. }
  82972. $beforeEndBraceIndex = $tokens->getPrevMeaningfulToken($endBraceIndex);
  82973. if ($tokens[$beforeEndBraceIndex]->equals(',')) {
  82974. array_shift($tokensToInsert);
  82975. $tokensToInsert[] = new Token(',');
  82976. }
  82977. $tokens->insertAt($beforeEndBraceIndex + 1, $tokensToInsert);
  82978. }
  82979. }
  82980. <?php
  82981. declare(strict_types=1);
  82982. namespace PhpCsFixer\Fixer\Semicolon;
  82983. use PhpCsFixer\AbstractFixer;
  82984. use PhpCsFixer\FixerDefinition\CodeSample;
  82985. use PhpCsFixer\FixerDefinition\FixerDefinition;
  82986. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  82987. use PhpCsFixer\Tokenizer\Tokens;
  82988. final class NoSinglelineWhitespaceBeforeSemicolonsFixer extends AbstractFixer
  82989. {
  82990. public function getDefinition(): FixerDefinitionInterface
  82991. {
  82992. return new FixerDefinition(
  82993. 'Single-line whitespace before closing semicolon are prohibited.',
  82994. [new CodeSample("<?php \$this->foo() ;\n")]
  82995. );
  82996. }
  82997. public function getPriority(): int
  82998. {
  82999. return 0;
  83000. }
  83001. public function isCandidate(Tokens $tokens): bool
  83002. {
  83003. return $tokens->isTokenKindFound(';');
  83004. }
  83005. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83006. {
  83007. foreach ($tokens as $index => $token) {
  83008. if (!$token->equals(';') || !$tokens[$index - 1]->isWhitespace(" \t")) {
  83009. continue;
  83010. }
  83011. if ($tokens[$index - 2]->equals(';')) {
  83012. $tokens->ensureWhitespaceAtIndex($index - 1, 0, ' ');
  83013. } elseif (!$tokens[$index - 2]->isComment()) {
  83014. $tokens->clearAt($index - 1);
  83015. }
  83016. }
  83017. }
  83018. }
  83019. <?php
  83020. declare(strict_types=1);
  83021. namespace PhpCsFixer\Fixer\Semicolon;
  83022. use PhpCsFixer\AbstractFixer;
  83023. use PhpCsFixer\FixerDefinition\CodeSample;
  83024. use PhpCsFixer\FixerDefinition\FixerDefinition;
  83025. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  83026. use PhpCsFixer\Tokenizer\CT;
  83027. use PhpCsFixer\Tokenizer\Tokens;
  83028. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  83029. final class NoEmptyStatementFixer extends AbstractFixer
  83030. {
  83031. public function getDefinition(): FixerDefinitionInterface
  83032. {
  83033. return new FixerDefinition(
  83034. 'Remove useless (semicolon) statements.',
  83035. [
  83036. new CodeSample("<?php \$a = 1;;\n"),
  83037. new CodeSample("<?php echo 1;2;\n"),
  83038. new CodeSample("<?php while(foo()){\n continue 1;\n}\n"),
  83039. ]
  83040. );
  83041. }
  83042. public function getPriority(): int
  83043. {
  83044. return 40;
  83045. }
  83046. public function isCandidate(Tokens $tokens): bool
  83047. {
  83048. return $tokens->isTokenKindFound(';');
  83049. }
  83050. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83051. {
  83052. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  83053. if ($tokens[$index]->isGivenKind([T_BREAK, T_CONTINUE])) {
  83054. $index = $tokens->getNextMeaningfulToken($index);
  83055. if ($tokens[$index]->equals([T_LNUMBER, '1'])) {
  83056. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83057. }
  83058. continue;
  83059. }
  83060. if ($tokens[$index]->isGivenKind(T_FOR)) {
  83061. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1;
  83062. continue;
  83063. }
  83064. if (!$tokens[$index]->equals(';')) {
  83065. continue;
  83066. }
  83067. $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
  83068. if ($tokens[$previousMeaningfulIndex]->equalsAny(['{', ';', [T_OPEN_TAG]])) {
  83069. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83070. continue;
  83071. }
  83072. if ($tokens[$previousMeaningfulIndex]->equals('}')) {
  83073. $this->fixSemicolonAfterCurlyBraceClose($tokens, $index, $previousMeaningfulIndex);
  83074. continue;
  83075. }
  83076. $nextIndex = $tokens->getNextMeaningfulToken($index);
  83077. if (null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_CLOSE)) {
  83078. continue;
  83079. }
  83080. $prePreviousMeaningfulIndex = $tokens->getPrevMeaningfulToken($previousMeaningfulIndex);
  83081. if (
  83082. $tokens[$prePreviousMeaningfulIndex]->equalsAny([';', '{', '}', [T_OPEN_TAG]])
  83083. && $tokens[$previousMeaningfulIndex]->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_DNUMBER, T_LNUMBER, T_STRING, T_VARIABLE])
  83084. ) {
  83085. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83086. $tokens->clearTokenAndMergeSurroundingWhitespace($previousMeaningfulIndex);
  83087. }
  83088. }
  83089. }
  83090. private function fixSemicolonAfterCurlyBraceClose(Tokens $tokens, int $index, int $curlyCloseIndex): void
  83091. {
  83092. static $beforeCurlyOpeningKinds = null;
  83093. if (null === $beforeCurlyOpeningKinds) {
  83094. $beforeCurlyOpeningKinds = [T_ELSE, T_FINALLY, T_NAMESPACE, T_OPEN_TAG];
  83095. }
  83096. $curlyOpeningIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $curlyCloseIndex);
  83097. $beforeCurlyOpeningIndex = $tokens->getPrevMeaningfulToken($curlyOpeningIndex);
  83098. if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind($beforeCurlyOpeningKinds) || $tokens[$beforeCurlyOpeningIndex]->equalsAny([';', '{', '}'])) {
  83099. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83100. return;
  83101. }
  83102. if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind(T_STRING)) {
  83103. $classyTestIndex = $tokens->getPrevMeaningfulToken($beforeCurlyOpeningIndex);
  83104. while ($tokens[$classyTestIndex]->equals(',') || $tokens[$classyTestIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_EXTENDS, T_IMPLEMENTS])) {
  83105. $classyTestIndex = $tokens->getPrevMeaningfulToken($classyTestIndex);
  83106. }
  83107. $tokensAnalyzer = new TokensAnalyzer($tokens);
  83108. if (
  83109. $tokens[$classyTestIndex]->isGivenKind(T_NAMESPACE)
  83110. || ($tokens[$classyTestIndex]->isClassy() && !$tokensAnalyzer->isAnonymousClass($classyTestIndex))
  83111. ) {
  83112. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83113. }
  83114. return;
  83115. }
  83116. if (!$tokens[$beforeCurlyOpeningIndex]->equals(')')) {
  83117. return;
  83118. }
  83119. $openingBraceIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeCurlyOpeningIndex);
  83120. $beforeOpeningBraceIndex = $tokens->getPrevMeaningfulToken($openingBraceIndex);
  83121. if ($tokens[$beforeOpeningBraceIndex]->isGivenKind([T_IF, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_SWITCH, T_CATCH, T_DECLARE])) {
  83122. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83123. return;
  83124. }
  83125. if ($tokens[$beforeOpeningBraceIndex]->isGivenKind(T_STRING)) {
  83126. $beforeStringIndex = $tokens->getPrevMeaningfulToken($beforeOpeningBraceIndex);
  83127. if ($tokens[$beforeStringIndex]->isGivenKind(T_FUNCTION)) {
  83128. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  83129. }
  83130. }
  83131. }
  83132. }
  83133. <?php
  83134. declare(strict_types=1);
  83135. namespace PhpCsFixer\Fixer\Semicolon;
  83136. use PhpCsFixer\AbstractFixer;
  83137. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  83138. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  83139. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  83140. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  83141. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  83142. use PhpCsFixer\FixerDefinition\CodeSample;
  83143. use PhpCsFixer\FixerDefinition\FixerDefinition;
  83144. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  83145. use PhpCsFixer\Preg;
  83146. use PhpCsFixer\Tokenizer\Token;
  83147. use PhpCsFixer\Tokenizer\Tokens;
  83148. /**
  83149. @phpstan-type
  83150. @phpstan-type
  83151. @implements
  83152. */
  83153. final class SpaceAfterSemicolonFixer extends AbstractFixer implements ConfigurableFixerInterface
  83154. {
  83155. /**
  83156. @use */
  83157. use ConfigurableFixerTrait;
  83158. public function getDefinition(): FixerDefinitionInterface
  83159. {
  83160. return new FixerDefinition(
  83161. 'Fix whitespace after a semicolon.',
  83162. [
  83163. new CodeSample(
  83164. "<?php
  83165. sample(); \$test = 1;
  83166. sample();\$test = 2;
  83167. for ( ;;++\$sample) {
  83168. }\n"
  83169. ),
  83170. new CodeSample("<?php\nfor (\$i = 0; ; ++\$i) {\n}\n", [
  83171. 'remove_in_empty_for_expressions' => true,
  83172. ]),
  83173. ]
  83174. );
  83175. }
  83176. public function getPriority(): int
  83177. {
  83178. return -1;
  83179. }
  83180. public function isCandidate(Tokens $tokens): bool
  83181. {
  83182. return $tokens->isTokenKindFound(';');
  83183. }
  83184. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  83185. {
  83186. return new FixerConfigurationResolver([
  83187. (new FixerOptionBuilder('remove_in_empty_for_expressions', 'Whether spaces should be removed for empty `for` expressions.'))
  83188. ->setAllowedTypes(['bool'])
  83189. ->setDefault(false)
  83190. ->getOption(),
  83191. ]);
  83192. }
  83193. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83194. {
  83195. $insideForParenthesesUntil = null;
  83196. for ($index = 0, $max = \count($tokens) - 1; $index < $max; ++$index) {
  83197. if (true === $this->configuration['remove_in_empty_for_expressions']) {
  83198. if ($tokens[$index]->isGivenKind(T_FOR)) {
  83199. $index = $tokens->getNextMeaningfulToken($index);
  83200. $insideForParenthesesUntil = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  83201. continue;
  83202. }
  83203. if ($index === $insideForParenthesesUntil) {
  83204. $insideForParenthesesUntil = null;
  83205. continue;
  83206. }
  83207. }
  83208. if (!$tokens[$index]->equals(';')) {
  83209. continue;
  83210. }
  83211. if (!$tokens[$index + 1]->isWhitespace()) {
  83212. if (
  83213. !$tokens[$index + 1]->equalsAny([')', [T_INLINE_HTML]]) && (
  83214. false === $this->configuration['remove_in_empty_for_expressions']
  83215. || !$tokens[$index + 1]->equals(';')
  83216. )
  83217. ) {
  83218. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  83219. ++$max;
  83220. }
  83221. continue;
  83222. }
  83223. if (
  83224. null !== $insideForParenthesesUntil
  83225. && ($tokens[$index + 2]->equals(';') || $index + 2 === $insideForParenthesesUntil)
  83226. && !Preg::match('/\R/', $tokens[$index + 1]->getContent())
  83227. ) {
  83228. $tokens->clearAt($index + 1);
  83229. continue;
  83230. }
  83231. if (
  83232. isset($tokens[$index + 2])
  83233. && !$tokens[$index + 1]->equals([T_WHITESPACE, ' '])
  83234. && $tokens[$index + 1]->isWhitespace(" \t")
  83235. && !$tokens[$index + 2]->isComment()
  83236. && !$tokens[$index + 2]->equals(')')
  83237. ) {
  83238. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  83239. }
  83240. }
  83241. }
  83242. }
  83243. <?php
  83244. declare(strict_types=1);
  83245. namespace PhpCsFixer\Fixer\Semicolon;
  83246. use PhpCsFixer\AbstractFixer;
  83247. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  83248. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  83249. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  83250. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  83251. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  83252. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  83253. use PhpCsFixer\FixerDefinition\CodeSample;
  83254. use PhpCsFixer\FixerDefinition\FixerDefinition;
  83255. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  83256. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  83257. use PhpCsFixer\Tokenizer\Token;
  83258. use PhpCsFixer\Tokenizer\Tokens;
  83259. /**
  83260. @phpstan-type
  83261. @phpstan-type
  83262. @implements
  83263. */
  83264. final class MultilineWhitespaceBeforeSemicolonsFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  83265. {
  83266. /**
  83267. @use */
  83268. use ConfigurableFixerTrait;
  83269. public const STRATEGY_NO_MULTI_LINE = 'no_multi_line';
  83270. public const STRATEGY_NEW_LINE_FOR_CHAINED_CALLS = 'new_line_for_chained_calls';
  83271. public function getDefinition(): FixerDefinitionInterface
  83272. {
  83273. return new FixerDefinition(
  83274. 'Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls.',
  83275. [
  83276. new CodeSample(
  83277. '<?php
  83278. function foo() {
  83279. return 1 + 2
  83280. ;
  83281. }
  83282. '
  83283. ),
  83284. new CodeSample(
  83285. '<?php
  83286. $object->method1()
  83287. ->method2()
  83288. ->method(3);
  83289. ',
  83290. ['strategy' => self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS]
  83291. ),
  83292. ]
  83293. );
  83294. }
  83295. public function getPriority(): int
  83296. {
  83297. return 0;
  83298. }
  83299. public function isCandidate(Tokens $tokens): bool
  83300. {
  83301. return $tokens->isTokenKindFound(';');
  83302. }
  83303. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  83304. {
  83305. return new FixerConfigurationResolver([
  83306. (new FixerOptionBuilder(
  83307. 'strategy',
  83308. 'Forbid multi-line whitespace or move the semicolon to the new line for chained calls.'
  83309. ))
  83310. ->setAllowedValues([self::STRATEGY_NO_MULTI_LINE, self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS])
  83311. ->setDefault(self::STRATEGY_NO_MULTI_LINE)
  83312. ->getOption(),
  83313. ]);
  83314. }
  83315. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83316. {
  83317. $lineEnding = $this->whitespacesConfig->getLineEnding();
  83318. for ($index = 0, $count = \count($tokens); $index < $count; ++$index) {
  83319. if ($tokens[$index]->isGivenKind(T_CONST)) {
  83320. $index = $tokens->getNextTokenOfKind($index, [';']);
  83321. continue;
  83322. }
  83323. if (!$tokens[$index]->equals(';')) {
  83324. continue;
  83325. }
  83326. $previousIndex = $index - 1;
  83327. $previous = $tokens[$previousIndex];
  83328. $indent = $this->findWhitespaceBeforeFirstCall($index, $tokens);
  83329. if (self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS === $this->configuration['strategy'] && null !== $indent) {
  83330. if ($previous->isWhitespace() && $previous->getContent() === $lineEnding.$indent) {
  83331. continue;
  83332. }
  83333. if ($previous->isWhitespace()) {
  83334. $tokens->clearAt($previousIndex);
  83335. }
  83336. $tokens->clearAt($index);
  83337. $index = $this->getNewLineIndex($index, $tokens);
  83338. $newline = new Token([T_WHITESPACE, $lineEnding.$indent]);
  83339. $tokens->insertAt($index++, [$newline, new Token(';')]);
  83340. } else {
  83341. if (!$previous->isWhitespace() || !str_contains($previous->getContent(), "\n")) {
  83342. continue;
  83343. }
  83344. $content = $previous->getContent();
  83345. if (str_starts_with($content, $lineEnding) && $tokens[$index - 2]->isComment()) {
  83346. $tokens->clearAt($previousIndex);
  83347. $tokens->clearAt($index);
  83348. $significantTokenIndex = $this->getPreviousSignificantTokenIndex($index, $tokens);
  83349. $tokens->insertAt($significantTokenIndex + 1, [new Token(';')]);
  83350. } else {
  83351. $tokens->clearAt($previousIndex);
  83352. }
  83353. }
  83354. }
  83355. }
  83356. private function getNewLineIndex(int $index, Tokens $tokens): int
  83357. {
  83358. $lineEnding = $this->whitespacesConfig->getLineEnding();
  83359. for ($index, $count = \count($tokens); $index < $count; ++$index) {
  83360. if (!$tokens[$index]->isWhitespace() && !$tokens[$index]->isComment()) {
  83361. break;
  83362. }
  83363. if (false !== strstr($tokens[$index]->getContent(), $lineEnding)) {
  83364. return $index;
  83365. }
  83366. }
  83367. return $index;
  83368. }
  83369. private function getPreviousSignificantTokenIndex(int $index, Tokens $tokens): int
  83370. {
  83371. $stopTokens = [
  83372. T_LNUMBER,
  83373. T_DNUMBER,
  83374. T_STRING,
  83375. T_VARIABLE,
  83376. T_CONSTANT_ENCAPSED_STRING,
  83377. ];
  83378. for ($index; $index > 0; --$index) {
  83379. if ($tokens[$index]->isGivenKind($stopTokens) || $tokens[$index]->equals(')')) {
  83380. return $index;
  83381. }
  83382. }
  83383. return $index;
  83384. }
  83385. private function findWhitespaceBeforeFirstCall(int $index, Tokens $tokens): ?string
  83386. {
  83387. $isMultilineCall = false;
  83388. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  83389. while (!$tokens[$prevIndex]->equalsAny([';', ':', '{', '}', [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO], [T_ELSE]])) {
  83390. $index = $prevIndex;
  83391. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  83392. $blockType = Tokens::detectBlockType($tokens[$index]);
  83393. if (null !== $blockType && !$blockType['isStart']) {
  83394. $prevIndex = $tokens->findBlockStart($blockType['type'], $index);
  83395. continue;
  83396. }
  83397. if ($tokens[$index]->isObjectOperator() || $tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  83398. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  83399. $isMultilineCall = $isMultilineCall || $tokens->isPartialCodeMultiline($prevIndex, $index);
  83400. }
  83401. }
  83402. return $isMultilineCall ? WhitespacesAnalyzer::detectIndent($tokens, $index) : null;
  83403. }
  83404. }
  83405. <?php
  83406. declare(strict_types=1);
  83407. namespace PhpCsFixer\Fixer\Semicolon;
  83408. use PhpCsFixer\AbstractFixer;
  83409. use PhpCsFixer\FixerDefinition\CodeSample;
  83410. use PhpCsFixer\FixerDefinition\FixerDefinition;
  83411. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  83412. use PhpCsFixer\Tokenizer\Token;
  83413. use PhpCsFixer\Tokenizer\Tokens;
  83414. final class SemicolonAfterInstructionFixer extends AbstractFixer
  83415. {
  83416. public function getDefinition(): FixerDefinitionInterface
  83417. {
  83418. return new FixerDefinition(
  83419. 'Instructions must be terminated with a semicolon.',
  83420. [new CodeSample("<?php echo 1 ?>\n")]
  83421. );
  83422. }
  83423. public function getPriority(): int
  83424. {
  83425. return 2;
  83426. }
  83427. public function isCandidate(Tokens $tokens): bool
  83428. {
  83429. return $tokens->isTokenKindFound(T_CLOSE_TAG);
  83430. }
  83431. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83432. {
  83433. for ($index = \count($tokens) - 1; $index > 1; --$index) {
  83434. if (!$tokens[$index]->isGivenKind(T_CLOSE_TAG)) {
  83435. continue;
  83436. }
  83437. $prev = $tokens->getPrevMeaningfulToken($index);
  83438. if ($tokens[$prev]->equalsAny([';', '{', '}', ':', [T_OPEN_TAG]])) {
  83439. continue;
  83440. }
  83441. $tokens->insertAt($prev + 1, new Token(';'));
  83442. }
  83443. }
  83444. }
  83445. <?php
  83446. declare(strict_types=1);
  83447. namespace PhpCsFixer\Fixer;
  83448. use PhpCsFixer\AbstractFixer;
  83449. use PhpCsFixer\DocBlock\DocBlock;
  83450. use PhpCsFixer\DocBlock\Line;
  83451. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  83452. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  83453. use PhpCsFixer\Tokenizer\Analyzer\FullyQualifiedNameAnalyzer;
  83454. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  83455. use PhpCsFixer\Tokenizer\Analyzer\PhpUnitTestCaseAnalyzer;
  83456. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  83457. use PhpCsFixer\Tokenizer\CT;
  83458. use PhpCsFixer\Tokenizer\FCT;
  83459. use PhpCsFixer\Tokenizer\Token;
  83460. use PhpCsFixer\Tokenizer\Tokens;
  83461. abstract class AbstractPhpUnitFixer extends AbstractFixer
  83462. {
  83463. private const DOC_BLOCK_MODIFIERS = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_COMMENT, FCT::T_ATTRIBUTE, FCT::T_READONLY];
  83464. private const ATTRIBUTE_MODIFIERS = [T_FINAL, FCT::T_READONLY];
  83465. public function isCandidate(Tokens $tokens): bool
  83466. {
  83467. return $tokens->isAllTokenKindsFound([T_CLASS, T_STRING]);
  83468. }
  83469. final protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83470. {
  83471. foreach ((new PhpUnitTestCaseAnalyzer())->findPhpUnitClasses($tokens) as $indices) {
  83472. $this->applyPhpUnitClassFix($tokens, $indices[0], $indices[1]);
  83473. }
  83474. }
  83475. abstract protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void;
  83476. final protected function getDocBlockIndex(Tokens $tokens, int $index): int
  83477. {
  83478. do {
  83479. $index = $tokens->getPrevNonWhitespace($index);
  83480. if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  83481. $index = $tokens->getPrevTokenOfKind($index, [[T_ATTRIBUTE]]);
  83482. }
  83483. } while ($tokens[$index]->isGivenKind(self::DOC_BLOCK_MODIFIERS));
  83484. return $index;
  83485. }
  83486. final protected function ensureIsDocBlockWithAnnotation(
  83487. Tokens $tokens,
  83488. int $index,
  83489. string $annotation,
  83490. array $preventingAnnotations,
  83491. array $preventingAttributes
  83492. ): void {
  83493. $docBlockIndex = $this->getDocBlockIndex($tokens, $index);
  83494. if (self::isPreventedByAttribute($tokens, $index, $preventingAttributes)) {
  83495. return;
  83496. }
  83497. if ($this->isPHPDoc($tokens, $docBlockIndex)) {
  83498. $this->updateDocBlockIfNeeded($tokens, $docBlockIndex, $annotation, $preventingAnnotations);
  83499. } else {
  83500. $this->createDocBlock($tokens, $docBlockIndex, $annotation);
  83501. }
  83502. }
  83503. final protected function isPHPDoc(Tokens $tokens, int $index): bool
  83504. {
  83505. return $tokens[$index]->isGivenKind(T_DOC_COMMENT);
  83506. }
  83507. protected function getPreviousAssertCall(Tokens $tokens, int $startIndex, int $endIndex): iterable
  83508. {
  83509. $functionsAnalyzer = new FunctionsAnalyzer();
  83510. for ($index = $endIndex; $index > $startIndex; --$index) {
  83511. $index = $tokens->getPrevTokenOfKind($index, [[T_STRING]]);
  83512. if (null === $index) {
  83513. return;
  83514. }
  83515. $loweredContent = strtolower($tokens[$index]->getContent());
  83516. if (!str_starts_with($loweredContent, 'assert')) {
  83517. continue;
  83518. }
  83519. $openBraceIndex = $tokens->getNextMeaningfulToken($index);
  83520. if (!$tokens[$openBraceIndex]->equals('(')) {
  83521. continue;
  83522. }
  83523. if (!$functionsAnalyzer->isTheSameClassCall($tokens, $index)) {
  83524. continue;
  83525. }
  83526. yield [
  83527. 'index' => $index,
  83528. 'loweredName' => $loweredContent,
  83529. 'openBraceIndex' => $openBraceIndex,
  83530. 'closeBraceIndex' => $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBraceIndex),
  83531. ];
  83532. }
  83533. }
  83534. final protected function isTestAttributePresent(Tokens $tokens, int $index): bool
  83535. {
  83536. $attributeIndex = $tokens->getPrevTokenOfKind($index, ['{', [FCT::T_ATTRIBUTE]]);
  83537. if (!$tokens[$attributeIndex]->isGivenKind(FCT::T_ATTRIBUTE)) {
  83538. return false;
  83539. }
  83540. $fullyQualifiedNameAnalyzer = new FullyQualifiedNameAnalyzer($tokens);
  83541. foreach (AttributeAnalyzer::collect($tokens, $attributeIndex) as $attributeAnalysis) {
  83542. foreach ($attributeAnalysis->getAttributes() as $attribute) {
  83543. $attributeName = strtolower($fullyQualifiedNameAnalyzer->getFullyQualifiedName($attribute['name'], $attribute['start'], NamespaceUseAnalysis::TYPE_CLASS));
  83544. if ('phpunit\framework\attributes\test' === $attributeName) {
  83545. return true;
  83546. }
  83547. }
  83548. }
  83549. return false;
  83550. }
  83551. private function createDocBlock(Tokens $tokens, int $docBlockIndex, string $annotation): void
  83552. {
  83553. $lineEnd = $this->whitespacesConfig->getLineEnding();
  83554. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  83555. $toInsert = [
  83556. new Token([T_DOC_COMMENT, "/**{$lineEnd}{$originalIndent} * @{$annotation}{$lineEnd}{$originalIndent} */"]),
  83557. new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
  83558. ];
  83559. $index = $tokens->getNextMeaningfulToken($docBlockIndex);
  83560. $tokens->insertAt($index, $toInsert);
  83561. if (!$tokens[$index - 1]->isGivenKind(T_WHITESPACE)) {
  83562. $extraNewLines = $this->whitespacesConfig->getLineEnding();
  83563. if (!$tokens[$index - 1]->isGivenKind(T_OPEN_TAG)) {
  83564. $extraNewLines .= $this->whitespacesConfig->getLineEnding();
  83565. }
  83566. $tokens->insertAt($index, [
  83567. new Token([T_WHITESPACE, $extraNewLines.WhitespacesAnalyzer::detectIndent($tokens, $index)]),
  83568. ]);
  83569. }
  83570. }
  83571. private function updateDocBlockIfNeeded(
  83572. Tokens $tokens,
  83573. int $docBlockIndex,
  83574. string $annotation,
  83575. array $preventingAnnotations
  83576. ): void {
  83577. $doc = new DocBlock($tokens[$docBlockIndex]->getContent());
  83578. foreach ($preventingAnnotations as $preventingAnnotation) {
  83579. if ([] !== $doc->getAnnotationsOfType($preventingAnnotation)) {
  83580. return;
  83581. }
  83582. }
  83583. $doc = $this->makeDocBlockMultiLineIfNeeded($doc, $tokens, $docBlockIndex, $annotation);
  83584. $lines = $this->addInternalAnnotation($doc, $tokens, $docBlockIndex, $annotation);
  83585. $lines = implode('', $lines);
  83586. $tokens->getNamespaceDeclarations();
  83587. $tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
  83588. }
  83589. private static function isPreventedByAttribute(Tokens $tokens, int $index, array $preventingAttributes): bool
  83590. {
  83591. if ([] === $preventingAttributes) {
  83592. return false;
  83593. }
  83594. do {
  83595. $index = $tokens->getPrevMeaningfulToken($index);
  83596. } while ($tokens[$index]->isGivenKind(self::ATTRIBUTE_MODIFIERS));
  83597. if (!$tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  83598. return false;
  83599. }
  83600. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  83601. $fullyQualifiedNameAnalyzer = new FullyQualifiedNameAnalyzer($tokens);
  83602. foreach (AttributeAnalyzer::collect($tokens, $index) as $attributeAnalysis) {
  83603. foreach ($attributeAnalysis->getAttributes() as $attribute) {
  83604. if (\in_array(strtolower($fullyQualifiedNameAnalyzer->getFullyQualifiedName($attribute['name'], $attribute['start'], NamespaceUseAnalysis::TYPE_CLASS)), $preventingAttributes, true)) {
  83605. return true;
  83606. }
  83607. }
  83608. }
  83609. return false;
  83610. }
  83611. private function addInternalAnnotation(DocBlock $docBlock, Tokens $tokens, int $docBlockIndex, string $annotation): array
  83612. {
  83613. $lines = $docBlock->getLines();
  83614. $originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $docBlockIndex);
  83615. $lineEnd = $this->whitespacesConfig->getLineEnding();
  83616. array_splice($lines, -1, 0, $originalIndent.' * @'.$annotation.$lineEnd);
  83617. return $lines;
  83618. }
  83619. private function makeDocBlockMultiLineIfNeeded(DocBlock $doc, Tokens $tokens, int $docBlockIndex, string $annotation): DocBlock
  83620. {
  83621. $lines = $doc->getLines();
  83622. if (1 === \count($lines) && [] === $doc->getAnnotationsOfType($annotation)) {
  83623. $indent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
  83624. $doc->makeMultiLine($indent, $this->whitespacesConfig->getLineEnding());
  83625. return $doc;
  83626. }
  83627. return $doc;
  83628. }
  83629. }
  83630. <?php
  83631. declare(strict_types=1);
  83632. namespace PhpCsFixer\Fixer\Import;
  83633. use PhpCsFixer\AbstractFixer;
  83634. use PhpCsFixer\DocBlock\TypeExpression;
  83635. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  83636. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  83637. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  83638. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  83639. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  83640. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  83641. use PhpCsFixer\FixerDefinition\CodeSample;
  83642. use PhpCsFixer\FixerDefinition\FixerDefinition;
  83643. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  83644. use PhpCsFixer\Preg;
  83645. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  83646. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  83647. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  83648. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  83649. use PhpCsFixer\Tokenizer\CT;
  83650. use PhpCsFixer\Tokenizer\FCT;
  83651. use PhpCsFixer\Tokenizer\Processor\ImportProcessor;
  83652. use PhpCsFixer\Tokenizer\Token;
  83653. use PhpCsFixer\Tokenizer\Tokens;
  83654. /**
  83655. @phpstan-type
  83656. @phpstan-type
  83657. @phpstan-type
  83658. @implements
  83659. @phpstan-import-type
  83660. */
  83661. final class FullyQualifiedStrictTypesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  83662. {
  83663. /**
  83664. @use */
  83665. use ConfigurableFixerTrait;
  83666. private const REGEX_CLASS = '(?:\\\?+'.TypeExpression::REGEX_IDENTIFIER
  83667. .'(\\\\'.TypeExpression::REGEX_IDENTIFIER.')*+)';
  83668. private const CLASSY_KINDS = [T_CLASS, T_INTERFACE, T_TRAIT, FCT::T_ENUM];
  83669. private ?array $discoveredSymbols;
  83670. private array $symbolsForImport = [];
  83671. private array $reservedIdentifiersByLevel;
  83672. private array $cacheUsesLast = [];
  83673. private array $cacheUseNameByShortNameLower;
  83674. private array $cacheUseShortNameByNameLower;
  83675. public function getDefinition(): FixerDefinitionInterface
  83676. {
  83677. return new FixerDefinition(
  83678. 'Removes the leading part of fully qualified symbol references if a given symbol is imported or belongs to the current namespace.',
  83679. [
  83680. new CodeSample(
  83681. '<?php
  83682. use Foo\Bar;
  83683. use Foo\Bar\Baz;
  83684. use Foo\OtherClass;
  83685. use Foo\SomeContract;
  83686. use Foo\SomeException;
  83687. /**
  83688. * @see \Foo\Bar\Baz
  83689. */
  83690. class SomeClass extends \Foo\OtherClass implements \Foo\SomeContract
  83691. {
  83692. /**
  83693. * @var \Foo\Bar\Baz
  83694. */
  83695. public $baz;
  83696. /**
  83697. * @param \Foo\Bar\Baz $baz
  83698. */
  83699. public function __construct($baz) {
  83700. $this->baz = $baz;
  83701. }
  83702. /**
  83703. * @return \Foo\Bar\Baz
  83704. */
  83705. public function getBaz() {
  83706. return $this->baz;
  83707. }
  83708. public function doX(\Foo\Bar $foo, \Exception $e): \Foo\Bar\Baz
  83709. {
  83710. try {}
  83711. catch (\Foo\SomeException $e) {}
  83712. }
  83713. }
  83714. '
  83715. ),
  83716. new CodeSample(
  83717. '<?php
  83718. class SomeClass
  83719. {
  83720. public function doY(Foo\NotImported $u, \Foo\NotImported $v)
  83721. {
  83722. }
  83723. }
  83724. ',
  83725. ['leading_backslash_in_global_namespace' => true]
  83726. ),
  83727. new CodeSample(
  83728. '<?php
  83729. namespace {
  83730. use Foo\A;
  83731. try {
  83732. foo();
  83733. } catch (\Exception|\Foo\A $e) {
  83734. }
  83735. }
  83736. namespace Foo\Bar {
  83737. class SomeClass implements \Foo\Bar\Baz
  83738. {
  83739. }
  83740. }
  83741. ',
  83742. ['leading_backslash_in_global_namespace' => true]
  83743. ),
  83744. new CodeSample(
  83745. '<?php
  83746. namespace Foo\Test;
  83747. class Foo extends \Other\BaseClass implements \Other\Interface1, \Other\Interface2
  83748. {
  83749. /** @var \Other\PropertyPhpDoc */
  83750. private $array;
  83751. public function __construct(\Other\FunctionArgument $arg) {}
  83752. public function foo(): \Other\FunctionReturnType
  83753. {
  83754. try {
  83755. \Other\StaticFunctionCall::bar();
  83756. } catch (\Other\CaughtThrowable $e) {}
  83757. }
  83758. }
  83759. ',
  83760. ['import_symbols' => true]
  83761. ),
  83762. ]
  83763. );
  83764. }
  83765. public function getPriority(): int
  83766. {
  83767. return 7;
  83768. }
  83769. public function isCandidate(Tokens $tokens): bool
  83770. {
  83771. return $tokens->isAnyTokenKindsFound([
  83772. CT::T_USE_TRAIT,
  83773. FCT::T_ATTRIBUTE,
  83774. T_CATCH,
  83775. T_DOUBLE_COLON,
  83776. T_DOC_COMMENT,
  83777. T_EXTENDS,
  83778. T_FUNCTION,
  83779. T_IMPLEMENTS,
  83780. T_INSTANCEOF,
  83781. T_NEW,
  83782. T_VARIABLE,
  83783. ]);
  83784. }
  83785. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  83786. {
  83787. return new FixerConfigurationResolver([
  83788. (new FixerOptionBuilder(
  83789. 'leading_backslash_in_global_namespace',
  83790. 'Whether FQCN is prefixed with backslash when that FQCN is used in global namespace context.'
  83791. ))
  83792. ->setAllowedTypes(['bool'])
  83793. ->setDefault(false)
  83794. ->getOption(),
  83795. (new FixerOptionBuilder(
  83796. 'import_symbols',
  83797. 'Whether FQCNs should be automatically imported.'
  83798. ))
  83799. ->setAllowedTypes(['bool'])
  83800. ->setDefault(false)
  83801. ->getOption(),
  83802. (new FixerOptionBuilder(
  83803. 'phpdoc_tags',
  83804. 'Collection of PHPDoc annotation tags where FQCNs should be processed. As of now only simple tags with `@tag \F\Q\C\N` format are supported (no complex types).'
  83805. ))
  83806. ->setAllowedTypes(['string[]'])
  83807. ->setDefault([
  83808. 'param',
  83809. 'phpstan-param',
  83810. 'phpstan-property',
  83811. 'phpstan-property-read',
  83812. 'phpstan-property-write',
  83813. 'phpstan-return',
  83814. 'phpstan-var',
  83815. 'property',
  83816. 'property-read',
  83817. 'property-write',
  83818. 'psalm-param',
  83819. 'psalm-property',
  83820. 'psalm-property-read',
  83821. 'psalm-property-write',
  83822. 'psalm-return',
  83823. 'psalm-var',
  83824. 'return',
  83825. 'see',
  83826. 'throws',
  83827. 'var',
  83828. ])
  83829. ->getOption(),
  83830. ]);
  83831. }
  83832. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  83833. {
  83834. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  83835. $functionsAnalyzer = new FunctionsAnalyzer();
  83836. $this->symbolsForImport = [];
  83837. foreach ($tokens->getNamespaceDeclarations() as $namespaceIndex => $namespace) {
  83838. $namespace = $tokens->getNamespaceDeclarations()[$namespaceIndex];
  83839. $namespaceName = $namespace->getFullName();
  83840. $uses = [];
  83841. $lastUse = null;
  83842. foreach ($namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace, true) as $use) {
  83843. if (!$use->isClass()) {
  83844. continue;
  83845. }
  83846. $uses[$use->getHumanFriendlyType()][ltrim($use->getFullName(), '\\')] = $use->getShortName();
  83847. $lastUse = $use;
  83848. }
  83849. $indexDiff = 0;
  83850. foreach (true === $this->configuration['import_symbols'] ? [true, false] : [false] as $discoverSymbolsPhase) {
  83851. $this->discoveredSymbols = $discoverSymbolsPhase ? [] : null;
  83852. $openedCurlyBrackets = 0;
  83853. $this->reservedIdentifiersByLevel = [];
  83854. for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex() + $indexDiff; ++$index) {
  83855. $origSize = \count($tokens);
  83856. if ($tokens[$index]->equals('{')) {
  83857. ++$openedCurlyBrackets;
  83858. } if ($tokens[$index]->equals('}')) {
  83859. unset($this->reservedIdentifiersByLevel[$openedCurlyBrackets]);
  83860. --$openedCurlyBrackets;
  83861. } elseif ($discoverSymbolsPhase && $tokens[$index]->isGivenKind(self::CLASSY_KINDS)) {
  83862. $this->fixNextName($tokens, $index, $uses, $namespaceName);
  83863. } elseif ($tokens[$index]->isGivenKind(T_FUNCTION)) {
  83864. $this->fixFunction($functionsAnalyzer, $tokens, $index, $uses, $namespaceName);
  83865. } elseif ($tokens[$index]->isGivenKind([T_EXTENDS, T_IMPLEMENTS])) {
  83866. $this->fixExtendsImplements($tokens, $index, $uses, $namespaceName);
  83867. } elseif ($tokens[$index]->isGivenKind(T_CATCH)) {
  83868. $this->fixCatch($tokens, $index, $uses, $namespaceName);
  83869. } elseif ($tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  83870. $this->fixPrevName($tokens, $index, $uses, $namespaceName);
  83871. } elseif ($tokens[$index]->isGivenKind([T_INSTANCEOF, T_NEW, CT::T_USE_TRAIT, CT::T_TYPE_COLON])) {
  83872. $this->fixNextName($tokens, $index, $uses, $namespaceName);
  83873. } elseif ($tokens[$index]->isGivenKind(T_VARIABLE)) {
  83874. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  83875. if (null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_STRING)) {
  83876. $this->fixPrevName($tokens, $index, $uses, $namespaceName);
  83877. }
  83878. } elseif ($tokens[$index]->isGivenKind(FCT::T_ATTRIBUTE)) {
  83879. $this->fixAttribute($tokens, $index, $uses, $namespaceName);
  83880. } elseif ($discoverSymbolsPhase && $tokens[$index]->isComment() && Preg::match('/#\[\s*('.self::REGEX_CLASS.')/', $tokens[$index]->getContent(), $matches)) {
  83881. $attributeClass = $matches[1];
  83882. $this->determineShortType($attributeClass, 'class', $uses, $namespaceName);
  83883. } elseif ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  83884. Preg::matchAll('/\*\h*@(?:psalm-|phpstan-)?(?:template(?:-covariant|-contravariant)?|(?:import-)?type)\h+('.TypeExpression::REGEX_IDENTIFIER.')(?!\S)/i', $tokens[$index]->getContent(), $matches);
  83885. foreach ($matches[1] as $reservedIdentifier) {
  83886. $this->reservedIdentifiersByLevel[$openedCurlyBrackets + 1][$reservedIdentifier] = true;
  83887. }
  83888. $this->fixPhpDoc($tokens, $index, $uses, $namespaceName);
  83889. }
  83890. $indexDiff += \count($tokens) - $origSize;
  83891. }
  83892. $this->reservedIdentifiersByLevel = [];
  83893. if ($discoverSymbolsPhase) {
  83894. $this->setupUsesFromDiscoveredSymbols($uses, $namespaceName);
  83895. }
  83896. }
  83897. if ([] !== $this->symbolsForImport) {
  83898. if (null !== $lastUse) {
  83899. $atIndex = $lastUse->getEndIndex() + 1;
  83900. } elseif (0 !== $namespace->getEndIndex()) {
  83901. $atIndex = $namespace->getEndIndex() + 1;
  83902. } else {
  83903. $firstTokenIndex = $tokens->getNextMeaningfulToken($namespace->getScopeStartIndex());
  83904. if (null !== $firstTokenIndex && $tokens[$firstTokenIndex]->isGivenKind(T_DECLARE)) {
  83905. $atIndex = $tokens->getNextTokenOfKind($firstTokenIndex, [';']) + 1;
  83906. } else {
  83907. $atIndex = $namespace->getScopeStartIndex() + 1;
  83908. }
  83909. }
  83910. $this->createImportProcessor()->insertImports($tokens, $this->symbolsForImport, $atIndex);
  83911. $this->symbolsForImport = [];
  83912. }
  83913. }
  83914. }
  83915. private function refreshUsesCache(array $uses): void
  83916. {
  83917. if ($this->cacheUsesLast === $uses) {
  83918. return;
  83919. }
  83920. $this->cacheUsesLast = $uses;
  83921. $this->cacheUseNameByShortNameLower = [];
  83922. $this->cacheUseShortNameByNameLower = [];
  83923. foreach ($uses as $kind => $kindUses) {
  83924. foreach ($kindUses as $useLongName => $useShortName) {
  83925. $this->cacheUseNameByShortNameLower[$kind][strtolower($useShortName)] = $useLongName;
  83926. /**
  83927. @phpstan-ignore
  83928. */
  83929. $normalisedUseLongName = strtolower($useLongName);
  83930. $this->cacheUseShortNameByNameLower[$kind][$normalisedUseLongName] = $useShortName;
  83931. }
  83932. }
  83933. }
  83934. private function isReservedIdentifier(string $symbol): bool
  83935. {
  83936. if (str_contains($symbol, '\\')) {
  83937. return false;
  83938. }
  83939. if ((new TypeAnalysis($symbol))->isReservedType()) {
  83940. return true;
  83941. }
  83942. foreach ($this->reservedIdentifiersByLevel as $reservedIdentifiers) {
  83943. if (isset($reservedIdentifiers[$symbol])) {
  83944. return true;
  83945. }
  83946. }
  83947. return false;
  83948. }
  83949. private function resolveSymbol(string $symbol, string $importKind, array $uses, string $namespaceName): string
  83950. {
  83951. if (str_starts_with($symbol, '\\')) {
  83952. return substr($symbol, 1);
  83953. }
  83954. if ($this->isReservedIdentifier($symbol)) {
  83955. return $symbol;
  83956. }
  83957. $this->refreshUsesCache($uses);
  83958. $symbolArr = explode('\\', $symbol, 2);
  83959. $shortStartNameLower = strtolower($symbolArr[0]);
  83960. if (isset($this->cacheUseNameByShortNameLower[$importKind][$shortStartNameLower])) {
  83961. return $this->cacheUseNameByShortNameLower[$importKind][$shortStartNameLower].(isset($symbolArr[1]) ? '\\'.$symbolArr[1] : '');
  83962. }
  83963. return ('' !== $namespaceName ? $namespaceName.'\\' : '').$symbol;
  83964. }
  83965. private function shortenSymbol(string $fqcn, string $importKind, array $uses, string $namespaceName): string
  83966. {
  83967. if ($this->isReservedIdentifier($fqcn)) {
  83968. return $fqcn;
  83969. }
  83970. $this->refreshUsesCache($uses);
  83971. $res = null;
  83972. $iMin = 0;
  83973. if (str_starts_with($fqcn, $namespaceName.'\\')) {
  83974. $tmpRes = substr($fqcn, \strlen($namespaceName) + 1);
  83975. if (!isset($this->cacheUseNameByShortNameLower[$importKind][strtolower(explode('\\', $tmpRes, 2)[0])]) && !$this->isReservedIdentifier($tmpRes)) {
  83976. $res = $tmpRes;
  83977. $iMin = substr_count($namespaceName, '\\') + 1;
  83978. }
  83979. }
  83980. $tmp = $fqcn;
  83981. for ($i = substr_count($fqcn, '\\'); $i >= $iMin; --$i) {
  83982. if (isset($this->cacheUseShortNameByNameLower[$importKind][strtolower($tmp)])) {
  83983. $tmpRes = $this->cacheUseShortNameByNameLower[$importKind][strtolower($tmp)].substr($fqcn, \strlen($tmp));
  83984. if (!$this->isReservedIdentifier($tmpRes)) {
  83985. $res = $tmpRes;
  83986. break;
  83987. }
  83988. }
  83989. if ($i > 0) {
  83990. $tmp = substr($tmp, 0, strrpos($tmp, '\\'));
  83991. }
  83992. }
  83993. if (null === $res) {
  83994. $res = $fqcn;
  83995. if ('' !== $namespaceName
  83996. || true === $this->configuration['leading_backslash_in_global_namespace']
  83997. || isset($this->cacheUseNameByShortNameLower[$importKind][strtolower(explode('\\', $res, 2)[0])])
  83998. ) {
  83999. $res = '\\'.$res;
  84000. }
  84001. }
  84002. return $res;
  84003. }
  84004. private function setupUsesFromDiscoveredSymbols(array &$uses, string $namespaceName): void
  84005. {
  84006. foreach ($this->discoveredSymbols as $kind => $discoveredSymbols) {
  84007. $discoveredFqcnByShortNameLower = [];
  84008. if ('' === $namespaceName) {
  84009. foreach ($discoveredSymbols as $symbol) {
  84010. if (!str_starts_with($symbol, '\\')) {
  84011. $shortStartName = explode('\\', ltrim($symbol, '\\'), 2)[0];
  84012. $shortStartNameLower = strtolower($shortStartName);
  84013. $discoveredFqcnByShortNameLower[$kind][$shortStartNameLower] = $this->resolveSymbol($shortStartName, $kind, $uses, $namespaceName);
  84014. }
  84015. }
  84016. }
  84017. foreach ($uses[$kind] ?? [] as $useLongName => $useShortName) {
  84018. $discoveredFqcnByShortNameLower[$kind][strtolower($useShortName)] = $useLongName;
  84019. }
  84020. $useByShortNameLower = [];
  84021. foreach ($uses[$kind] ?? [] as $useShortName) {
  84022. $useByShortNameLower[strtolower($useShortName)] = true;
  84023. }
  84024. uasort($discoveredSymbols, static function ($a, $b) {
  84025. $res = str_starts_with($a, '\\') <=> str_starts_with($b, '\\');
  84026. if (0 !== $res) {
  84027. return $res;
  84028. }
  84029. return substr_count($a, '\\') <=> substr_count($b, '\\');
  84030. });
  84031. foreach ($discoveredSymbols as $symbol) {
  84032. while (true) {
  84033. $shortEndNameLower = strtolower(str_contains($symbol, '\\') ? substr($symbol, strrpos($symbol, '\\') + 1) : $symbol);
  84034. if (!isset($discoveredFqcnByShortNameLower[$kind][$shortEndNameLower])) {
  84035. $shortStartNameLower = strtolower(explode('\\', ltrim($symbol, '\\'), 2)[0]);
  84036. if (str_starts_with($symbol, '\\') || ('' === $namespaceName && !isset($useByShortNameLower[$shortStartNameLower]))
  84037. || !str_contains($symbol, '\\')
  84038. ) {
  84039. $discoveredFqcnByShortNameLower[$kind][$shortEndNameLower] = $this->resolveSymbol($symbol, $kind, $uses, $namespaceName);
  84040. break;
  84041. }
  84042. }
  84043. if (str_starts_with($symbol, '\\') || '' === $namespaceName || !str_contains($symbol, '\\')) {
  84044. break;
  84045. }
  84046. $symbol = substr($symbol, 0, strrpos($symbol, '\\'));
  84047. }
  84048. }
  84049. foreach ($uses[$kind] ?? [] as $useLongName => $useShortName) {
  84050. $discoveredLongName = $discoveredFqcnByShortNameLower[$kind][strtolower($useShortName)] ?? null;
  84051. if (strtolower($discoveredLongName) === strtolower($useLongName)) {
  84052. unset($discoveredFqcnByShortNameLower[$kind][strtolower($useShortName)]);
  84053. }
  84054. }
  84055. foreach ($discoveredFqcnByShortNameLower[$kind] ?? [] as $fqcn) {
  84056. $shortenedName = ltrim($this->shortenSymbol($fqcn, $kind, [], $namespaceName), '\\');
  84057. if (str_contains($shortenedName, '\\')) {
  84058. $shortEndName = str_contains($fqcn, '\\') ? substr($fqcn, strrpos($fqcn, '\\') + 1) : $fqcn;
  84059. $uses[$kind][$fqcn] = $shortEndName;
  84060. $this->symbolsForImport[$kind][$shortEndName] = $fqcn;
  84061. }
  84062. }
  84063. if (isset($this->symbolsForImport[$kind])) {
  84064. ksort($this->symbolsForImport[$kind], SORT_NATURAL);
  84065. }
  84066. }
  84067. }
  84068. private function fixFunction(FunctionsAnalyzer $functionsAnalyzer, Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84069. {
  84070. $arguments = $functionsAnalyzer->getFunctionArguments($tokens, $index);
  84071. foreach ($arguments as $i => $argument) {
  84072. $argument = $functionsAnalyzer->getFunctionArguments($tokens, $index)[$i];
  84073. if ($argument->hasTypeAnalysis()) {
  84074. $this->replaceByShortType($tokens, $argument->getTypeAnalysis(), $uses, $namespaceName);
  84075. }
  84076. }
  84077. $returnTypeAnalysis = $functionsAnalyzer->getFunctionReturnType($tokens, $index);
  84078. if (null !== $returnTypeAnalysis) {
  84079. $this->replaceByShortType($tokens, $returnTypeAnalysis, $uses, $namespaceName);
  84080. }
  84081. }
  84082. private function fixPhpDoc(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84083. {
  84084. $allowedTags = $this->configuration['phpdoc_tags'];
  84085. if ([] === $allowedTags) {
  84086. return;
  84087. }
  84088. $phpDoc = $tokens[$index];
  84089. $phpDocContent = $phpDoc->getContent();
  84090. $phpDocContentNew = Preg::replaceCallback('/([*{]\h*@)(\S+)(\h+)('.TypeExpression::REGEX_TYPES.')(?!(?!\})\S)/', function ($matches) use ($allowedTags, $uses, $namespaceName) {
  84091. if (!\in_array($matches[2], $allowedTags, true)) {
  84092. return $matches[0];
  84093. }
  84094. return $matches[1].$matches[2].$matches[3].$this->fixPhpDocType($matches[4], $uses, $namespaceName);
  84095. }, $phpDocContent);
  84096. if ($phpDocContentNew !== $phpDocContent) {
  84097. $tokens[$index] = new Token([T_DOC_COMMENT, $phpDocContentNew]);
  84098. }
  84099. }
  84100. private function fixPhpDocType(string $type, array $uses, string $namespaceName): string
  84101. {
  84102. $typeExpression = new TypeExpression($type, null, []);
  84103. $typeExpression = $typeExpression->mapTypes(function (TypeExpression $type) use ($uses, $namespaceName) {
  84104. $currentTypeValue = $type->toString();
  84105. if ($type->isCompositeType() || !Preg::match('/^'.self::REGEX_CLASS.'$/', $currentTypeValue) || \in_array($currentTypeValue, ['min', 'max'], true)) {
  84106. return $type;
  84107. }
  84108. $shortTokens = $this->determineShortType($currentTypeValue, 'class', $uses, $namespaceName);
  84109. if (null === $shortTokens) {
  84110. return $type;
  84111. }
  84112. $newTypeValue = implode('', array_map(
  84113. static fn (Token $token) => $token->getContent(),
  84114. $shortTokens
  84115. ));
  84116. return $currentTypeValue === $newTypeValue
  84117. ? $type
  84118. : new TypeExpression($newTypeValue, null, []);
  84119. });
  84120. return $typeExpression->toString();
  84121. }
  84122. private function fixExtendsImplements(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84123. {
  84124. $isExtends = $tokens[$index]->equals([T_EXTENDS]);
  84125. $index = $tokens->getNextMeaningfulToken($index);
  84126. $typeStartIndex = null;
  84127. $typeEndIndex = null;
  84128. while (true) {
  84129. if ($tokens[$index]->equalsAny([',', '{', [T_IMPLEMENTS]])) {
  84130. if (null !== $typeStartIndex) {
  84131. $index += $this->shortenClassIfPossible($tokens, $typeStartIndex, $typeEndIndex, $uses, $namespaceName);
  84132. }
  84133. $typeStartIndex = null;
  84134. if ($tokens[$index]->equalsAny($isExtends ? [[T_IMPLEMENTS], '{'] : ['{'])) {
  84135. break;
  84136. }
  84137. } else {
  84138. if (null === $typeStartIndex) {
  84139. $typeStartIndex = $index;
  84140. }
  84141. $typeEndIndex = $index;
  84142. }
  84143. $index = $tokens->getNextMeaningfulToken($index);
  84144. }
  84145. }
  84146. private function fixCatch(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84147. {
  84148. $index = $tokens->getNextMeaningfulToken($index);
  84149. $index = $tokens->getNextMeaningfulToken($index);
  84150. $typeStartIndex = null;
  84151. $typeEndIndex = null;
  84152. while (true) {
  84153. if ($tokens[$index]->equalsAny([')', [T_VARIABLE], [CT::T_TYPE_ALTERNATION]])) {
  84154. if (null === $typeStartIndex) {
  84155. break;
  84156. }
  84157. $index += $this->shortenClassIfPossible($tokens, $typeStartIndex, $typeEndIndex, $uses, $namespaceName);
  84158. $typeStartIndex = null;
  84159. if ($tokens[$index]->equals(')')) {
  84160. break;
  84161. }
  84162. } else {
  84163. if (null === $typeStartIndex) {
  84164. $typeStartIndex = $index;
  84165. }
  84166. $typeEndIndex = $index;
  84167. }
  84168. $index = $tokens->getNextMeaningfulToken($index);
  84169. }
  84170. }
  84171. private function fixAttribute(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84172. {
  84173. $attributeAnalysis = AttributeAnalyzer::collectOne($tokens, $index);
  84174. foreach ($attributeAnalysis->getAttributes() as $attribute) {
  84175. $index = $attribute['start'];
  84176. while ($tokens[$index]->equalsAny([[T_STRING], [T_NS_SEPARATOR]])) {
  84177. $index = $tokens->getPrevMeaningfulToken($index);
  84178. }
  84179. $this->fixNextName($tokens, $index, $uses, $namespaceName);
  84180. }
  84181. }
  84182. private function fixPrevName(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84183. {
  84184. $typeStartIndex = null;
  84185. $typeEndIndex = null;
  84186. while (true) {
  84187. $index = $tokens->getPrevMeaningfulToken($index);
  84188. if ($tokens[$index]->isObjectOperator()) {
  84189. break;
  84190. }
  84191. if ($tokens[$index]->equalsAny([[T_STRING], [T_NS_SEPARATOR]])) {
  84192. $typeStartIndex = $index;
  84193. if (null === $typeEndIndex) {
  84194. $typeEndIndex = $index;
  84195. }
  84196. } else {
  84197. if (null !== $typeEndIndex) {
  84198. $index += $this->shortenClassIfPossible($tokens, $typeStartIndex, $typeEndIndex, $uses, $namespaceName);
  84199. }
  84200. break;
  84201. }
  84202. }
  84203. }
  84204. private function fixNextName(Tokens $tokens, int $index, array $uses, string $namespaceName): void
  84205. {
  84206. $typeStartIndex = null;
  84207. $typeEndIndex = null;
  84208. while (true) {
  84209. $index = $tokens->getNextMeaningfulToken($index);
  84210. if ($tokens[$index]->equalsAny([[T_STRING], [T_NS_SEPARATOR]])) {
  84211. if (null === $typeStartIndex) {
  84212. $typeStartIndex = $index;
  84213. }
  84214. $typeEndIndex = $index;
  84215. } else {
  84216. if (null !== $typeStartIndex) {
  84217. $index += $this->shortenClassIfPossible($tokens, $typeStartIndex, $typeEndIndex, $uses, $namespaceName);
  84218. }
  84219. break;
  84220. }
  84221. }
  84222. }
  84223. private function shortenClassIfPossible(Tokens $tokens, int $typeStartIndex, int $typeEndIndex, array $uses, string $namespaceName): int
  84224. {
  84225. $content = $tokens->generatePartialCode($typeStartIndex, $typeEndIndex);
  84226. $newTokens = $this->determineShortType($content, 'class', $uses, $namespaceName);
  84227. if (null === $newTokens) {
  84228. return 0;
  84229. }
  84230. $tokens->overrideRange($typeStartIndex, $typeEndIndex, $newTokens);
  84231. return \count($newTokens) - ($typeEndIndex - $typeStartIndex) - 1;
  84232. }
  84233. private function replaceByShortType(Tokens $tokens, TypeAnalysis $type, array $uses, string $namespaceName): void
  84234. {
  84235. $typeStartIndex = $type->getStartIndex();
  84236. if ($tokens[$typeStartIndex]->isGivenKind(CT::T_NULLABLE_TYPE)) {
  84237. $typeStartIndex = $tokens->getNextMeaningfulToken($typeStartIndex);
  84238. }
  84239. $types = $this->getTypes($tokens, $typeStartIndex, $type->getEndIndex());
  84240. foreach ($types as [$startIndex, $endIndex]) {
  84241. $content = $tokens->generatePartialCode($startIndex, $endIndex);
  84242. $newTokens = $this->determineShortType($content, 'class', $uses, $namespaceName);
  84243. if (null !== $newTokens) {
  84244. $tokens->overrideRange($startIndex, $endIndex, $newTokens);
  84245. }
  84246. }
  84247. }
  84248. private function determineShortType(string $typeName, string $importKind, array $uses, string $namespaceName): ?array
  84249. {
  84250. if (null !== $this->discoveredSymbols) {
  84251. if (!$this->isReservedIdentifier($typeName)) {
  84252. $this->discoveredSymbols[$importKind][] = $typeName;
  84253. }
  84254. return null;
  84255. }
  84256. $fqcn = $this->resolveSymbol($typeName, $importKind, $uses, $namespaceName);
  84257. $shortenedType = $this->shortenSymbol($fqcn, $importKind, $uses, $namespaceName);
  84258. if ($shortenedType === $typeName) {
  84259. return null;
  84260. }
  84261. return $this->namespacedStringToTokens($shortenedType);
  84262. }
  84263. private function getTypes(Tokens $tokens, int $index, int $endIndex): iterable
  84264. {
  84265. $skipNextYield = false;
  84266. $typeStartIndex = $typeEndIndex = null;
  84267. while (true) {
  84268. if ($tokens[$index]->isGivenKind(CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN)) {
  84269. $index = $tokens->getNextMeaningfulToken($index);
  84270. $typeStartIndex = $typeEndIndex = null;
  84271. continue;
  84272. }
  84273. if (
  84274. $tokens[$index]->isGivenKind([CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE])
  84275. || $index > $endIndex
  84276. ) {
  84277. if (!$skipNextYield && null !== $typeStartIndex) {
  84278. $origCount = \count($tokens);
  84279. yield [$typeStartIndex, $typeEndIndex];
  84280. $endIndex += \count($tokens) - $origCount;
  84281. $skipNextYield = true;
  84282. $index = $typeEndIndex = $typeStartIndex;
  84283. } else {
  84284. $skipNextYield = false;
  84285. $index = $tokens->getNextMeaningfulToken($index);
  84286. $typeStartIndex = $typeEndIndex = null;
  84287. }
  84288. if ($index > $endIndex) {
  84289. break;
  84290. }
  84291. continue;
  84292. }
  84293. if (null === $typeStartIndex) {
  84294. $typeStartIndex = $index;
  84295. }
  84296. $typeEndIndex = $index;
  84297. $index = $tokens->getNextMeaningfulToken($index);
  84298. }
  84299. }
  84300. private function namespacedStringToTokens(string $input): array
  84301. {
  84302. $tokens = [];
  84303. if (str_starts_with($input, '\\')) {
  84304. $tokens[] = new Token([T_NS_SEPARATOR, '\\']);
  84305. $input = substr($input, 1);
  84306. }
  84307. $parts = explode('\\', $input);
  84308. foreach ($parts as $index => $part) {
  84309. $tokens[] = new Token([T_STRING, $part]);
  84310. if ($index !== \count($parts) - 1) {
  84311. $tokens[] = new Token([T_NS_SEPARATOR, '\\']);
  84312. }
  84313. }
  84314. return $tokens;
  84315. }
  84316. private function createImportProcessor(): ImportProcessor
  84317. {
  84318. return new ImportProcessor($this->whitespacesConfig);
  84319. }
  84320. }
  84321. <?php
  84322. declare(strict_types=1);
  84323. namespace PhpCsFixer\Fixer\Import;
  84324. use PhpCsFixer\AbstractFixer;
  84325. use PhpCsFixer\FixerDefinition\CodeSample;
  84326. use PhpCsFixer\FixerDefinition\FixerDefinition;
  84327. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  84328. use PhpCsFixer\Preg;
  84329. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  84330. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  84331. use PhpCsFixer\Tokenizer\Analyzer\GotoLabelAnalyzer;
  84332. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  84333. use PhpCsFixer\Tokenizer\CT;
  84334. use PhpCsFixer\Tokenizer\FCT;
  84335. use PhpCsFixer\Tokenizer\Token;
  84336. use PhpCsFixer\Tokenizer\Tokens;
  84337. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  84338. final class NoUnusedImportsFixer extends AbstractFixer
  84339. {
  84340. private const TOKENS_NOT_BEFORE_FUNCTION_CALL = [T_NEW, FCT::T_ATTRIBUTE];
  84341. public function getDefinition(): FixerDefinitionInterface
  84342. {
  84343. return new FixerDefinition(
  84344. 'Unused `use` statements must be removed.',
  84345. [new CodeSample("<?php\nuse \\DateTime;\nuse \\Exception;\n\nnew DateTime();\n")]
  84346. );
  84347. }
  84348. public function getPriority(): int
  84349. {
  84350. return -10;
  84351. }
  84352. public function isCandidate(Tokens $tokens): bool
  84353. {
  84354. return $tokens->isTokenKindFound(T_USE);
  84355. }
  84356. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  84357. {
  84358. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens, true);
  84359. if (0 === \count($useDeclarations)) {
  84360. return;
  84361. }
  84362. foreach ($tokens->getNamespaceDeclarations() as $namespace) {
  84363. $currentNamespaceUseDeclarations = [];
  84364. $currentNamespaceUseDeclarationIndices = [];
  84365. foreach ($useDeclarations as $useDeclaration) {
  84366. if ($useDeclaration->getStartIndex() >= $namespace->getScopeStartIndex() && $useDeclaration->getEndIndex() <= $namespace->getScopeEndIndex()) {
  84367. $currentNamespaceUseDeclarations[] = $useDeclaration;
  84368. $currentNamespaceUseDeclarationIndices[$useDeclaration->getStartIndex()] = $useDeclaration->getEndIndex();
  84369. }
  84370. }
  84371. foreach ($currentNamespaceUseDeclarations as $useDeclaration) {
  84372. if (!$this->isImportUsed($tokens, $namespace, $useDeclaration, $currentNamespaceUseDeclarationIndices)) {
  84373. $this->removeUseDeclaration($tokens, $useDeclaration);
  84374. }
  84375. }
  84376. $this->removeUsesInSameNamespace($tokens, $currentNamespaceUseDeclarations, $namespace);
  84377. }
  84378. }
  84379. private function isImportUsed(Tokens $tokens, NamespaceAnalysis $namespace, NamespaceUseAnalysis $import, array $ignoredIndices): bool
  84380. {
  84381. $analyzer = new TokensAnalyzer($tokens);
  84382. $gotoLabelAnalyzer = new GotoLabelAnalyzer();
  84383. $namespaceEndIndex = $namespace->getScopeEndIndex();
  84384. $inAttribute = false;
  84385. for ($index = $namespace->getScopeStartIndex(); $index <= $namespaceEndIndex; ++$index) {
  84386. $token = $tokens[$index];
  84387. if ($token->isGivenKind(FCT::T_ATTRIBUTE)) {
  84388. $inAttribute = true;
  84389. continue;
  84390. }
  84391. if ($token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  84392. $inAttribute = false;
  84393. continue;
  84394. }
  84395. if (isset($ignoredIndices[$index])) {
  84396. $index = $ignoredIndices[$index];
  84397. continue;
  84398. }
  84399. if ($token->isGivenKind(T_STRING)) {
  84400. if (0 !== strcasecmp($import->getShortName(), $token->getContent())) {
  84401. continue;
  84402. }
  84403. $prevMeaningfulToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  84404. if ($prevMeaningfulToken->isGivenKind(T_NAMESPACE)) {
  84405. $index = $tokens->getNextTokenOfKind($index, [';', '{', [T_CLOSE_TAG]]);
  84406. continue;
  84407. }
  84408. if (
  84409. $prevMeaningfulToken->isGivenKind([T_NS_SEPARATOR, T_FUNCTION, T_CONST, T_DOUBLE_COLON])
  84410. || $prevMeaningfulToken->isObjectOperator()
  84411. ) {
  84412. continue;
  84413. }
  84414. if ($inAttribute) {
  84415. return true;
  84416. }
  84417. $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($index);
  84418. if ($gotoLabelAnalyzer->belongsToGoToLabel($tokens, $nextMeaningfulIndex)) {
  84419. continue;
  84420. }
  84421. $nextMeaningfulToken = $tokens[$nextMeaningfulIndex];
  84422. if ($analyzer->isConstantInvocation($index)) {
  84423. $type = NamespaceUseAnalysis::TYPE_CONSTANT;
  84424. } elseif ($nextMeaningfulToken->equals('(') && !$prevMeaningfulToken->isGivenKind(self::TOKENS_NOT_BEFORE_FUNCTION_CALL)) {
  84425. $type = NamespaceUseAnalysis::TYPE_FUNCTION;
  84426. } else {
  84427. $type = NamespaceUseAnalysis::TYPE_CLASS;
  84428. }
  84429. if ($import->getType() === $type) {
  84430. return true;
  84431. }
  84432. continue;
  84433. }
  84434. if ($token->isComment()
  84435. && Preg::match(
  84436. '/(?<![[:alnum:]\$_])(?<!\\\)'.$import->getShortName().'(?![[:alnum:]_])/i',
  84437. $token->getContent()
  84438. )
  84439. ) {
  84440. return true;
  84441. }
  84442. }
  84443. return false;
  84444. }
  84445. private function removeUseDeclaration(
  84446. Tokens $tokens,
  84447. NamespaceUseAnalysis $useDeclaration,
  84448. bool $forceCompleteRemoval = false
  84449. ): void {
  84450. [$start, $end] = ($useDeclaration->isInMulti() && !$forceCompleteRemoval)
  84451. ? [$useDeclaration->getChunkStartIndex(), $useDeclaration->getChunkEndIndex()]
  84452. : [$useDeclaration->getStartIndex(), $useDeclaration->getEndIndex()];
  84453. $loopStartIndex = $useDeclaration->isInMulti() || $forceCompleteRemoval ? $end : $end - 1;
  84454. for ($index = $loopStartIndex; $index >= $start; --$index) {
  84455. if ($tokens[$index]->isComment()) {
  84456. continue;
  84457. }
  84458. if (!$tokens[$index]->isWhitespace() || !str_contains($tokens[$index]->getContent(), "\n")) {
  84459. $tokens->clearAt($index);
  84460. continue;
  84461. }
  84462. $prevIndex = $tokens->getPrevNonWhitespace($index);
  84463. if ($tokens[$prevIndex]->isComment()) {
  84464. $content = $tokens[$index]->getContent();
  84465. $tokens[$index] = new Token([T_WHITESPACE, substr($content, strrpos($content, "\n"))]);
  84466. } else {
  84467. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  84468. }
  84469. }
  84470. if (!$forceCompleteRemoval && $useDeclaration->isInMulti()) {
  84471. $this->cleanUpAfterImportChunkRemoval($tokens, $useDeclaration);
  84472. return;
  84473. }
  84474. if ($tokens[$useDeclaration->getEndIndex()]->equals(';')) {
  84475. $tokens->clearAt($useDeclaration->getEndIndex());
  84476. }
  84477. $this->cleanUpSurroundingNewLines($tokens, $useDeclaration);
  84478. }
  84479. private function removeUsesInSameNamespace(Tokens $tokens, array $useDeclarations, NamespaceAnalysis $namespaceDeclaration): void
  84480. {
  84481. $namespace = $namespaceDeclaration->getFullName();
  84482. $nsLength = \strlen($namespace.'\\');
  84483. foreach ($useDeclarations as $useDeclaration) {
  84484. if ($useDeclaration->isAliased()) {
  84485. continue;
  84486. }
  84487. $useDeclarationFullName = ltrim($useDeclaration->getFullName(), '\\');
  84488. if (!str_starts_with($useDeclarationFullName, $namespace.'\\')) {
  84489. continue;
  84490. }
  84491. $partName = substr($useDeclarationFullName, $nsLength);
  84492. if (!str_contains($partName, '\\')) {
  84493. $this->removeUseDeclaration($tokens, $useDeclaration);
  84494. }
  84495. }
  84496. }
  84497. private function cleanUpAfterImportChunkRemoval(Tokens $tokens, NamespaceUseAnalysis $useDeclaration): void
  84498. {
  84499. $beforeChunkIndex = $tokens->getPrevMeaningfulToken($useDeclaration->getChunkStartIndex());
  84500. $afterChunkIndex = $tokens->getNextMeaningfulToken($useDeclaration->getChunkEndIndex());
  84501. $hasNonEmptyTokenBefore = $this->scanForNonEmptyTokensUntilNewLineFound(
  84502. $tokens,
  84503. $afterChunkIndex,
  84504. -1
  84505. );
  84506. $hasNonEmptyTokenAfter = $this->scanForNonEmptyTokensUntilNewLineFound(
  84507. $tokens,
  84508. $afterChunkIndex,
  84509. 1
  84510. );
  84511. $mergingSurroundingWhitespaceIsSafe = $hasNonEmptyTokenBefore[1] || $hasNonEmptyTokenAfter[1];
  84512. $clearToken = static function (int $index) use ($tokens, $mergingSurroundingWhitespaceIsSafe): void {
  84513. if ($mergingSurroundingWhitespaceIsSafe) {
  84514. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  84515. } else {
  84516. $tokens->clearAt($index);
  84517. }
  84518. };
  84519. if ($tokens[$afterChunkIndex]->equals(',')) {
  84520. $clearToken($afterChunkIndex);
  84521. } elseif ($tokens[$beforeChunkIndex]->equals(',')) {
  84522. $clearToken($beforeChunkIndex);
  84523. }
  84524. for ($index = $beforeChunkIndex; $index <= $afterChunkIndex; ++$index) {
  84525. if (null === $tokens[$index]->getId() || !$tokens[$index]->isWhitespace(' ')) {
  84526. continue;
  84527. }
  84528. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  84529. if (
  84530. $tokens[$nextTokenIndex]->equals(',')
  84531. || $tokens[$nextTokenIndex]->equals(';')
  84532. || $tokens[$nextTokenIndex]->isGivenKind([CT::T_GROUP_IMPORT_BRACE_CLOSE])
  84533. ) {
  84534. $tokens->clearAt($index);
  84535. } else {
  84536. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  84537. }
  84538. $prevTokenIndex = $tokens->getPrevMeaningfulToken($index);
  84539. if ($tokens[$prevTokenIndex]->isGivenKind([CT::T_GROUP_IMPORT_BRACE_OPEN])) {
  84540. $tokens->clearAt($index);
  84541. }
  84542. }
  84543. $this->removeLineIfEmpty($tokens, $useDeclaration);
  84544. $this->removeImportStatementIfEmpty($tokens, $useDeclaration);
  84545. }
  84546. private function cleanUpSurroundingNewLines(Tokens $tokens, NamespaceUseAnalysis $useDeclaration): void
  84547. {
  84548. $prevIndex = $useDeclaration->getStartIndex() - 1;
  84549. $prevToken = $tokens[$prevIndex];
  84550. if ($prevToken->isWhitespace()) {
  84551. $content = rtrim($prevToken->getContent(), " \t");
  84552. $tokens->ensureWhitespaceAtIndex($prevIndex, 0, $content);
  84553. $prevToken = $tokens[$prevIndex];
  84554. }
  84555. if (!isset($tokens[$useDeclaration->getEndIndex() + 1])) {
  84556. return;
  84557. }
  84558. $nextIndex = $tokens->getNonEmptySibling($useDeclaration->getEndIndex(), 1);
  84559. if (null === $nextIndex) {
  84560. return;
  84561. }
  84562. $nextToken = $tokens[$nextIndex];
  84563. if ($nextToken->isWhitespace()) {
  84564. $content = Preg::replace(
  84565. "#^\r\n|^\n#",
  84566. '',
  84567. ltrim($nextToken->getContent(), " \t"),
  84568. 1
  84569. );
  84570. $tokens->ensureWhitespaceAtIndex($nextIndex, 0, $content);
  84571. $nextToken = $tokens[$nextIndex];
  84572. }
  84573. if ($prevToken->isWhitespace() && $nextToken->isWhitespace()) {
  84574. $content = $prevToken->getContent().$nextToken->getContent();
  84575. $tokens->ensureWhitespaceAtIndex($nextIndex, 0, $content);
  84576. $tokens->clearAt($prevIndex);
  84577. }
  84578. }
  84579. private function removeImportStatementIfEmpty(Tokens $tokens, NamespaceUseAnalysis $useDeclaration): void
  84580. {
  84581. $endingBraceIndex = $tokens->getPrevTokenOfKind(
  84582. $useDeclaration->getEndIndex(),
  84583. [[CT::T_GROUP_IMPORT_BRACE_CLOSE]]
  84584. );
  84585. if ($endingBraceIndex > $useDeclaration->getStartIndex()) {
  84586. $openingBraceIndex = $tokens->getPrevMeaningfulToken($endingBraceIndex);
  84587. if ($tokens[$openingBraceIndex]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  84588. $this->removeUseDeclaration($tokens, $useDeclaration, true);
  84589. }
  84590. }
  84591. $beforeSemicolonIndex = $tokens->getPrevMeaningfulToken($useDeclaration->getEndIndex());
  84592. if (
  84593. $tokens[$beforeSemicolonIndex]->isGivenKind([T_USE])
  84594. || \in_array($tokens[$beforeSemicolonIndex]->getContent(), ['function', 'const'], true)
  84595. ) {
  84596. $this->removeUseDeclaration($tokens, $useDeclaration, true);
  84597. }
  84598. }
  84599. private function removeLineIfEmpty(Tokens $tokens, NamespaceUseAnalysis $useAnalysis): void
  84600. {
  84601. if (!$useAnalysis->isInMulti()) {
  84602. return;
  84603. }
  84604. $hasNonEmptyTokenBefore = $this->scanForNonEmptyTokensUntilNewLineFound(
  84605. $tokens,
  84606. $useAnalysis->getChunkStartIndex(),
  84607. -1
  84608. );
  84609. $hasNonEmptyTokenAfter = $this->scanForNonEmptyTokensUntilNewLineFound(
  84610. $tokens,
  84611. $useAnalysis->getChunkEndIndex(),
  84612. 1
  84613. );
  84614. if (
  84615. \is_int($hasNonEmptyTokenBefore[0])
  84616. && !$hasNonEmptyTokenBefore[1]
  84617. && \is_int($hasNonEmptyTokenAfter[0])
  84618. && !$hasNonEmptyTokenAfter[1]
  84619. ) {
  84620. $tokens->clearRange($hasNonEmptyTokenBefore[0], $hasNonEmptyTokenAfter[0] - 1);
  84621. }
  84622. }
  84623. private function scanForNonEmptyTokensUntilNewLineFound(Tokens $tokens, int $index, int $direction): array
  84624. {
  84625. $hasNonEmptyToken = false;
  84626. $newLineTokenIndex = null;
  84627. while (\is_int($index)) {
  84628. $index = $tokens->getNonEmptySibling($index, $direction);
  84629. if (null === $index || null === $tokens[$index]->getId()) {
  84630. continue;
  84631. }
  84632. if (!$tokens[$index]->isWhitespace()) {
  84633. $hasNonEmptyToken = true;
  84634. } elseif (str_starts_with($tokens[$index]->getContent(), "\n")) {
  84635. $newLineTokenIndex = $index;
  84636. break;
  84637. }
  84638. }
  84639. return [$newLineTokenIndex, $hasNonEmptyToken];
  84640. }
  84641. }
  84642. <?php
  84643. declare(strict_types=1);
  84644. namespace PhpCsFixer\Fixer\Import;
  84645. use PhpCsFixer\AbstractFixer;
  84646. use PhpCsFixer\DocBlock\Annotation;
  84647. use PhpCsFixer\DocBlock\DocBlock;
  84648. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  84649. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  84650. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  84651. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  84652. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  84653. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  84654. use PhpCsFixer\FixerDefinition\CodeSample;
  84655. use PhpCsFixer\FixerDefinition\FixerDefinition;
  84656. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  84657. use PhpCsFixer\Preg;
  84658. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  84659. use PhpCsFixer\Tokenizer\Analyzer\ClassyAnalyzer;
  84660. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  84661. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  84662. use PhpCsFixer\Tokenizer\CT;
  84663. use PhpCsFixer\Tokenizer\Processor\ImportProcessor;
  84664. use PhpCsFixer\Tokenizer\Token;
  84665. use PhpCsFixer\Tokenizer\Tokens;
  84666. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  84667. /**
  84668. @phpstan-type
  84669. @phpstan-type
  84670. @implements
  84671. */
  84672. final class GlobalNamespaceImportFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  84673. {
  84674. /**
  84675. @use */
  84676. use ConfigurableFixerTrait;
  84677. private ImportProcessor $importProcessor;
  84678. public function __construct()
  84679. {
  84680. parent::__construct();
  84681. $this->importProcessor = new ImportProcessor($this->whitespacesConfig);
  84682. }
  84683. public function getDefinition(): FixerDefinitionInterface
  84684. {
  84685. return new FixerDefinition(
  84686. 'Imports or fully qualifies global classes/functions/constants.',
  84687. [
  84688. new CodeSample(
  84689. '<?php
  84690. namespace Foo;
  84691. $d = new \DateTimeImmutable();
  84692. '
  84693. ),
  84694. new CodeSample(
  84695. '<?php
  84696. namespace Foo;
  84697. if (\count($x)) {
  84698. /** @var \DateTimeImmutable $d */
  84699. $d = new \DateTimeImmutable();
  84700. $p = \M_PI;
  84701. }
  84702. ',
  84703. ['import_classes' => true, 'import_constants' => true, 'import_functions' => true]
  84704. ),
  84705. new CodeSample(
  84706. '<?php
  84707. namespace Foo;
  84708. use DateTimeImmutable;
  84709. use function count;
  84710. use const M_PI;
  84711. if (count($x)) {
  84712. /** @var DateTimeImmutable $d */
  84713. $d = new DateTimeImmutable();
  84714. $p = M_PI;
  84715. }
  84716. ',
  84717. ['import_classes' => false, 'import_constants' => false, 'import_functions' => false]
  84718. ),
  84719. ]
  84720. );
  84721. }
  84722. public function getPriority(): int
  84723. {
  84724. return 0;
  84725. }
  84726. public function isCandidate(Tokens $tokens): bool
  84727. {
  84728. return $tokens->isAnyTokenKindsFound([T_DOC_COMMENT, T_NS_SEPARATOR, T_USE])
  84729. && $tokens->isTokenKindFound(T_NAMESPACE)
  84730. && 1 === $tokens->countTokenKind(T_NAMESPACE)
  84731. && $tokens->isMonolithicPhp();
  84732. }
  84733. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  84734. {
  84735. $namespaceAnalyses = $tokens->getNamespaceDeclarations();
  84736. if (1 !== \count($namespaceAnalyses) || $namespaceAnalyses[0]->isGlobalNamespace()) {
  84737. return;
  84738. }
  84739. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  84740. $newImports = [];
  84741. if (true === $this->configuration['import_constants']) {
  84742. $newImports['const'] = $this->importConstants($tokens, $useDeclarations);
  84743. } elseif (false === $this->configuration['import_constants']) {
  84744. $this->fullyQualifyConstants($tokens, $useDeclarations);
  84745. }
  84746. if (true === $this->configuration['import_functions']) {
  84747. $newImports['function'] = $this->importFunctions($tokens, $useDeclarations);
  84748. } elseif (false === $this->configuration['import_functions']) {
  84749. $this->fullyQualifyFunctions($tokens, $useDeclarations);
  84750. }
  84751. if (true === $this->configuration['import_classes']) {
  84752. $newImports['class'] = $this->importClasses($tokens, $useDeclarations);
  84753. } elseif (false === $this->configuration['import_classes']) {
  84754. $this->fullyQualifyClasses($tokens, $useDeclarations);
  84755. }
  84756. if (\count($newImports) > 0) {
  84757. if (\count($useDeclarations) > 0) {
  84758. $useDeclaration = end($useDeclarations);
  84759. $atIndex = $useDeclaration->getEndIndex() + 1;
  84760. } else {
  84761. $namespace = $tokens->getNamespaceDeclarations()[0];
  84762. $atIndex = $namespace->getEndIndex() + 1;
  84763. }
  84764. $this->importProcessor->insertImports($tokens, $newImports, $atIndex);
  84765. }
  84766. }
  84767. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  84768. {
  84769. return new FixerConfigurationResolver([
  84770. (new FixerOptionBuilder('import_constants', 'Whether to import, not import or ignore global constants.'))
  84771. ->setDefault(null)
  84772. ->setAllowedTypes(['null', 'bool'])
  84773. ->getOption(),
  84774. (new FixerOptionBuilder('import_functions', 'Whether to import, not import or ignore global functions.'))
  84775. ->setDefault(null)
  84776. ->setAllowedTypes(['null', 'bool'])
  84777. ->getOption(),
  84778. (new FixerOptionBuilder('import_classes', 'Whether to import, not import or ignore global classes.'))
  84779. ->setDefault(true)
  84780. ->setAllowedTypes(['null', 'bool'])
  84781. ->getOption(),
  84782. ]);
  84783. }
  84784. private function importConstants(Tokens $tokens, array $useDeclarations): array
  84785. {
  84786. [$global, $other] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isConstant(), true);
  84787. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  84788. $token = $tokens[$index];
  84789. if ($token->isClassy()) {
  84790. $index = $tokens->getNextTokenOfKind($index, ['{']);
  84791. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  84792. continue;
  84793. }
  84794. if (!$token->isGivenKind(T_CONST)) {
  84795. continue;
  84796. }
  84797. $index = $tokens->getNextMeaningfulToken($index);
  84798. $other[$tokens[$index]->getContent()] = true;
  84799. }
  84800. $analyzer = new TokensAnalyzer($tokens);
  84801. $indices = [];
  84802. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  84803. $token = $tokens[$index];
  84804. if (!$token->isGivenKind(T_STRING)) {
  84805. continue;
  84806. }
  84807. $name = $token->getContent();
  84808. if (isset($other[$name])) {
  84809. continue;
  84810. }
  84811. if (!$analyzer->isConstantInvocation($index)) {
  84812. continue;
  84813. }
  84814. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  84815. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  84816. if (!isset($global[$name])) {
  84817. $other[$name] = true;
  84818. }
  84819. continue;
  84820. }
  84821. $prevIndex = $tokens->getPrevMeaningfulToken($nsSeparatorIndex);
  84822. if ($tokens[$prevIndex]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_STRING])) {
  84823. continue;
  84824. }
  84825. $indices[] = $index;
  84826. }
  84827. return $this->prepareImports($tokens, $indices, $global, $other, true);
  84828. }
  84829. private function importFunctions(Tokens $tokens, array $useDeclarations): array
  84830. {
  84831. [$global, $other] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isFunction(), false);
  84832. foreach ($this->findFunctionDeclarations($tokens, 0, $tokens->count() - 1) as $name) {
  84833. $other[strtolower($name)] = true;
  84834. }
  84835. $analyzer = new FunctionsAnalyzer();
  84836. $indices = [];
  84837. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  84838. $token = $tokens[$index];
  84839. if (!$token->isGivenKind(T_STRING)) {
  84840. continue;
  84841. }
  84842. $name = strtolower($token->getContent());
  84843. if (isset($other[$name])) {
  84844. continue;
  84845. }
  84846. if (!$analyzer->isGlobalFunctionCall($tokens, $index)) {
  84847. continue;
  84848. }
  84849. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  84850. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  84851. if (!isset($global[$name])) {
  84852. $other[$name] = true;
  84853. }
  84854. continue;
  84855. }
  84856. $indices[] = $index;
  84857. }
  84858. return $this->prepareImports($tokens, $indices, $global, $other, false);
  84859. }
  84860. private function importClasses(Tokens $tokens, array $useDeclarations): array
  84861. {
  84862. [$global, $other] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isClass(), false);
  84863. $docBlocks = [];
  84864. for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
  84865. $token = $tokens[$index];
  84866. if ($token->isGivenKind(T_DOC_COMMENT)) {
  84867. $docBlocks[$index] = new DocBlock($token->getContent());
  84868. $this->traverseDocBlockTypes($docBlocks[$index], static function (string $type) use ($global, &$other): void {
  84869. if (str_contains($type, '\\')) {
  84870. return;
  84871. }
  84872. $name = strtolower($type);
  84873. if (!isset($global[$name])) {
  84874. $other[$name] = true;
  84875. }
  84876. });
  84877. }
  84878. if (!$token->isClassy()) {
  84879. continue;
  84880. }
  84881. $index = $tokens->getNextMeaningfulToken($index);
  84882. if ($tokens[$index]->isGivenKind(T_STRING)) {
  84883. $other[strtolower($tokens[$index]->getContent())] = true;
  84884. }
  84885. }
  84886. $analyzer = new ClassyAnalyzer();
  84887. $indices = [];
  84888. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  84889. $token = $tokens[$index];
  84890. if (!$token->isGivenKind(T_STRING)) {
  84891. continue;
  84892. }
  84893. $name = strtolower($token->getContent());
  84894. if (isset($other[$name])) {
  84895. continue;
  84896. }
  84897. if (!$analyzer->isClassyInvocation($tokens, $index)) {
  84898. continue;
  84899. }
  84900. $nsSeparatorIndex = $tokens->getPrevMeaningfulToken($index);
  84901. if (!$tokens[$nsSeparatorIndex]->isGivenKind(T_NS_SEPARATOR)) {
  84902. if (!isset($global[$name])) {
  84903. $other[$name] = true;
  84904. }
  84905. continue;
  84906. }
  84907. if ($tokens[$tokens->getPrevMeaningfulToken($nsSeparatorIndex)]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_STRING])) {
  84908. continue;
  84909. }
  84910. $indices[] = $index;
  84911. }
  84912. $imports = [];
  84913. foreach ($docBlocks as $index => $docBlock) {
  84914. $changed = $this->traverseDocBlockTypes($docBlock, static function (string $type) use ($global, $other, &$imports): string {
  84915. if ('\\' !== $type[0]) {
  84916. return $type;
  84917. }
  84918. $name = substr($type, 1);
  84919. $checkName = strtolower($name);
  84920. if (str_contains($checkName, '\\') || isset($other[$checkName])) {
  84921. return $type;
  84922. }
  84923. if (isset($global[$checkName])) {
  84924. return \is_string($global[$checkName]) ? $global[$checkName] : $name;
  84925. }
  84926. $imports[$checkName] = $name;
  84927. return $name;
  84928. });
  84929. if ($changed) {
  84930. $tokens[$index] = new Token([T_DOC_COMMENT, $docBlock->getContent()]);
  84931. }
  84932. }
  84933. return array_merge($imports, $this->prepareImports($tokens, $indices, $global, $other, false));
  84934. }
  84935. private function prepareImports(Tokens $tokens, array $indices, array $global, array $other, bool $caseSensitive): array
  84936. {
  84937. $imports = [];
  84938. foreach ($indices as $index) {
  84939. $name = $tokens[$index]->getContent();
  84940. $checkName = $caseSensitive ? $name : strtolower($name);
  84941. if (isset($other[$checkName])) {
  84942. continue;
  84943. }
  84944. if (!isset($global[$checkName])) {
  84945. $imports[$checkName] = $name;
  84946. } elseif (\is_string($global[$checkName])) {
  84947. $tokens[$index] = new Token([T_STRING, $global[$checkName]]);
  84948. }
  84949. $tokens->clearAt($tokens->getPrevMeaningfulToken($index));
  84950. }
  84951. return $imports;
  84952. }
  84953. private function fullyQualifyConstants(Tokens $tokens, array $useDeclarations): void
  84954. {
  84955. if (!$tokens->isTokenKindFound(CT::T_CONST_IMPORT)) {
  84956. return;
  84957. }
  84958. [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isConstant() && !$declaration->isAliased(), true);
  84959. if ([] === $global) {
  84960. return;
  84961. }
  84962. $analyzer = new TokensAnalyzer($tokens);
  84963. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  84964. $token = $tokens[$index];
  84965. if (!$token->isGivenKind(T_STRING)) {
  84966. continue;
  84967. }
  84968. if (!isset($global[$token->getContent()])) {
  84969. continue;
  84970. }
  84971. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  84972. continue;
  84973. }
  84974. if (!$analyzer->isConstantInvocation($index)) {
  84975. continue;
  84976. }
  84977. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  84978. }
  84979. }
  84980. private function fullyQualifyFunctions(Tokens $tokens, array $useDeclarations): void
  84981. {
  84982. if (!$tokens->isTokenKindFound(CT::T_FUNCTION_IMPORT)) {
  84983. return;
  84984. }
  84985. [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isFunction() && !$declaration->isAliased(), false);
  84986. if ([] === $global) {
  84987. return;
  84988. }
  84989. $analyzer = new FunctionsAnalyzer();
  84990. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  84991. $token = $tokens[$index];
  84992. if (!$token->isGivenKind(T_STRING)) {
  84993. continue;
  84994. }
  84995. if (!isset($global[strtolower($token->getContent())])) {
  84996. continue;
  84997. }
  84998. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  84999. continue;
  85000. }
  85001. if (!$analyzer->isGlobalFunctionCall($tokens, $index)) {
  85002. continue;
  85003. }
  85004. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  85005. }
  85006. }
  85007. private function fullyQualifyClasses(Tokens $tokens, array $useDeclarations): void
  85008. {
  85009. if (!$tokens->isTokenKindFound(T_USE)) {
  85010. return;
  85011. }
  85012. [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isClass() && !$declaration->isAliased(), false);
  85013. if ([] === $global) {
  85014. return;
  85015. }
  85016. $analyzer = new ClassyAnalyzer();
  85017. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  85018. $token = $tokens[$index];
  85019. if ($token->isGivenKind(T_DOC_COMMENT)) {
  85020. $doc = new DocBlock($token->getContent());
  85021. $changed = $this->traverseDocBlockTypes($doc, static function (string $type) use ($global): string {
  85022. if (!isset($global[strtolower($type)])) {
  85023. return $type;
  85024. }
  85025. return '\\'.$type;
  85026. });
  85027. if ($changed) {
  85028. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  85029. }
  85030. continue;
  85031. }
  85032. if (!$token->isGivenKind(T_STRING)) {
  85033. continue;
  85034. }
  85035. if (!isset($global[strtolower($token->getContent())])) {
  85036. continue;
  85037. }
  85038. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
  85039. continue;
  85040. }
  85041. if (!$analyzer->isClassyInvocation($tokens, $index)) {
  85042. continue;
  85043. }
  85044. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  85045. }
  85046. }
  85047. private function filterUseDeclarations(array $declarations, callable $callback, bool $caseSensitive): array
  85048. {
  85049. $global = [];
  85050. $other = [];
  85051. foreach ($declarations as $declaration) {
  85052. if (!$callback($declaration)) {
  85053. continue;
  85054. }
  85055. $fullName = ltrim($declaration->getFullName(), '\\');
  85056. if (str_contains($fullName, '\\')) {
  85057. $name = $caseSensitive ? $declaration->getShortName() : strtolower($declaration->getShortName());
  85058. $other[$name] = true;
  85059. continue;
  85060. }
  85061. $checkName = $caseSensitive ? $fullName : strtolower($fullName);
  85062. $alias = $declaration->getShortName();
  85063. $global[$checkName] = $alias === $fullName ? true : $alias;
  85064. }
  85065. return [$global, $other];
  85066. }
  85067. private function findFunctionDeclarations(Tokens $tokens, int $start, int $end): iterable
  85068. {
  85069. for ($index = $start; $index <= $end; ++$index) {
  85070. $token = $tokens[$index];
  85071. if ($token->isClassy()) {
  85072. $classStart = $tokens->getNextTokenOfKind($index, ['{']);
  85073. $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
  85074. for ($index = $classStart; $index <= $classEnd; ++$index) {
  85075. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  85076. continue;
  85077. }
  85078. $methodStart = $tokens->getNextTokenOfKind($index, ['{', ';']);
  85079. if ($tokens[$methodStart]->equals(';')) {
  85080. $index = $methodStart;
  85081. continue;
  85082. }
  85083. $methodEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $methodStart);
  85084. foreach ($this->findFunctionDeclarations($tokens, $methodStart, $methodEnd) as $function) {
  85085. yield $function;
  85086. }
  85087. $index = $methodEnd;
  85088. }
  85089. continue;
  85090. }
  85091. if (!$token->isGivenKind(T_FUNCTION)) {
  85092. continue;
  85093. }
  85094. $index = $tokens->getNextMeaningfulToken($index);
  85095. if ($tokens[$index]->isGivenKind(CT::T_RETURN_REF)) {
  85096. $index = $tokens->getNextMeaningfulToken($index);
  85097. }
  85098. if ($tokens[$index]->isGivenKind(T_STRING)) {
  85099. yield $tokens[$index]->getContent();
  85100. }
  85101. }
  85102. }
  85103. private function traverseDocBlockTypes(DocBlock $doc, callable $callback): bool
  85104. {
  85105. $annotations = $doc->getAnnotationsOfType(Annotation::getTagsWithTypes());
  85106. if (0 === \count($annotations)) {
  85107. return false;
  85108. }
  85109. $changed = false;
  85110. foreach ($annotations as $annotation) {
  85111. $types = $new = $annotation->getTypes();
  85112. foreach ($types as $i => $fullType) {
  85113. $newFullType = $fullType;
  85114. Preg::matchAll('/[\\\\\w]+(?![\\\\\w:])/', $fullType, $matches, PREG_OFFSET_CAPTURE);
  85115. foreach (array_reverse($matches[0]) as [$type, $offset]) {
  85116. $newType = $callback($type);
  85117. if (null !== $newType && $type !== $newType) {
  85118. $newFullType = substr_replace($newFullType, $newType, $offset, \strlen($type));
  85119. }
  85120. }
  85121. $new[$i] = $newFullType;
  85122. }
  85123. if ($types !== $new) {
  85124. $annotation->setTypes($new);
  85125. $changed = true;
  85126. }
  85127. }
  85128. return $changed;
  85129. }
  85130. }
  85131. <?php
  85132. declare(strict_types=1);
  85133. namespace PhpCsFixer\Fixer\Import;
  85134. use PhpCsFixer\AbstractFixer;
  85135. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  85136. use PhpCsFixer\Console\Application;
  85137. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  85138. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  85139. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  85140. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  85141. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  85142. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  85143. use PhpCsFixer\FixerDefinition\CodeSample;
  85144. use PhpCsFixer\FixerDefinition\FixerDefinition;
  85145. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  85146. use PhpCsFixer\Preg;
  85147. use PhpCsFixer\Tokenizer\CT;
  85148. use PhpCsFixer\Tokenizer\Token;
  85149. use PhpCsFixer\Tokenizer\Tokens;
  85150. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  85151. use PhpCsFixer\Utils;
  85152. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  85153. use Symfony\Component\OptionsResolver\Options;
  85154. /**
  85155. @phpstan-type
  85156. @phpstan-type
  85157. @phpstan-type
  85158. @implements
  85159. */
  85160. final class OrderedImportsFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  85161. {
  85162. /**
  85163. @use */
  85164. use ConfigurableFixerTrait;
  85165. public const IMPORT_TYPE_CLASS = 'class';
  85166. public const IMPORT_TYPE_CONST = 'const';
  85167. public const IMPORT_TYPE_FUNCTION = 'function';
  85168. public const SORT_ALPHA = 'alpha';
  85169. public const SORT_LENGTH = 'length';
  85170. public const SORT_NONE = 'none';
  85171. private const SUPPORTED_SORT_TYPES = [self::IMPORT_TYPE_CLASS, self::IMPORT_TYPE_CONST, self::IMPORT_TYPE_FUNCTION];
  85172. private const SUPPORTED_SORT_ALGORITHMS = [self::SORT_ALPHA, self::SORT_LENGTH, self::SORT_NONE];
  85173. public function getDefinition(): FixerDefinitionInterface
  85174. {
  85175. return new FixerDefinition(
  85176. 'Ordering `use` statements.',
  85177. [
  85178. new CodeSample(
  85179. "<?php\nuse function AAC;\nuse const AAB;\nuse AAA;\n"
  85180. ),
  85181. new CodeSample(
  85182. "<?php\nuse function Aaa;\nuse const AA;\n",
  85183. ['case_sensitive' => true]
  85184. ),
  85185. new CodeSample(
  85186. '<?php
  85187. use Acme\Bar;
  85188. use Bar1;
  85189. use Acme;
  85190. use Bar;
  85191. ',
  85192. ['sort_algorithm' => self::SORT_LENGTH]
  85193. ),
  85194. new CodeSample(
  85195. '<?php
  85196. use const AAAA;
  85197. use const BBB;
  85198. use Bar;
  85199. use AAC;
  85200. use Acme;
  85201. use function CCC\AA;
  85202. use function DDD;
  85203. ',
  85204. [
  85205. 'sort_algorithm' => self::SORT_LENGTH,
  85206. 'imports_order' => [
  85207. self::IMPORT_TYPE_CONST,
  85208. self::IMPORT_TYPE_CLASS,
  85209. self::IMPORT_TYPE_FUNCTION,
  85210. ],
  85211. ]
  85212. ),
  85213. new CodeSample(
  85214. '<?php
  85215. use const BBB;
  85216. use const AAAA;
  85217. use Acme;
  85218. use AAC;
  85219. use Bar;
  85220. use function DDD;
  85221. use function CCC\AA;
  85222. ',
  85223. [
  85224. 'sort_algorithm' => self::SORT_ALPHA,
  85225. 'imports_order' => [
  85226. self::IMPORT_TYPE_CONST,
  85227. self::IMPORT_TYPE_CLASS,
  85228. self::IMPORT_TYPE_FUNCTION,
  85229. ],
  85230. ]
  85231. ),
  85232. new CodeSample(
  85233. '<?php
  85234. use const BBB;
  85235. use const AAAA;
  85236. use function DDD;
  85237. use function CCC\AA;
  85238. use Acme;
  85239. use AAC;
  85240. use Bar;
  85241. ',
  85242. [
  85243. 'sort_algorithm' => self::SORT_NONE,
  85244. 'imports_order' => [
  85245. self::IMPORT_TYPE_CONST,
  85246. self::IMPORT_TYPE_CLASS,
  85247. self::IMPORT_TYPE_FUNCTION,
  85248. ],
  85249. ]
  85250. ),
  85251. ]
  85252. );
  85253. }
  85254. public function getPriority(): int
  85255. {
  85256. return -30;
  85257. }
  85258. public function isCandidate(Tokens $tokens): bool
  85259. {
  85260. return $tokens->isTokenKindFound(T_USE);
  85261. }
  85262. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  85263. {
  85264. $tokensAnalyzer = new TokensAnalyzer($tokens);
  85265. $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
  85266. foreach (array_reverse($namespacesImports) as $usesPerNamespaceIndices) {
  85267. $count = \count($usesPerNamespaceIndices);
  85268. if (0 === $count) {
  85269. continue;
  85270. }
  85271. if (1 === $count) {
  85272. $this->setNewOrder($tokens, $this->getNewOrder($usesPerNamespaceIndices, $tokens));
  85273. continue;
  85274. }
  85275. $groupUsesOffset = 0;
  85276. $groupUses = [$groupUsesOffset => [$usesPerNamespaceIndices[0]]];
  85277. for ($index = 0; $index < $count - 1; ++$index) {
  85278. $nextGroupUse = $tokens->getNextTokenOfKind($usesPerNamespaceIndices[$index], [';', [T_CLOSE_TAG]]);
  85279. if ($tokens[$nextGroupUse]->isGivenKind(T_CLOSE_TAG)) {
  85280. $nextGroupUse = $tokens->getNextTokenOfKind($usesPerNamespaceIndices[$index], [[T_OPEN_TAG]]);
  85281. }
  85282. $nextGroupUse = $tokens->getNextMeaningfulToken($nextGroupUse);
  85283. if ($nextGroupUse !== $usesPerNamespaceIndices[$index + 1]) {
  85284. $groupUses[++$groupUsesOffset] = [];
  85285. }
  85286. $groupUses[$groupUsesOffset][] = $usesPerNamespaceIndices[$index + 1];
  85287. }
  85288. for ($index = $groupUsesOffset; $index >= 0; --$index) {
  85289. $this->setNewOrder($tokens, $this->getNewOrder($groupUses[$index], $tokens));
  85290. }
  85291. }
  85292. }
  85293. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  85294. {
  85295. $supportedSortTypes = self::SUPPORTED_SORT_TYPES;
  85296. $fixerName = $this->getName();
  85297. return new FixerConfigurationResolver([
  85298. (new FixerOptionBuilder('sort_algorithm', 'Whether the statements should be sorted alphabetically or by length (*deprecated*), or not sorted.'))
  85299. ->setAllowedValues(self::SUPPORTED_SORT_ALGORITHMS)
  85300. ->setDefault(self::SORT_ALPHA)
  85301. ->setNormalizer(static function (Options $options, ?string $value) use ($fixerName): ?string {
  85302. if (self::SORT_LENGTH === $value) {
  85303. Utils::triggerDeprecation(new InvalidFixerConfigurationException($fixerName, \sprintf(
  85304. 'Option "sort_algorithm:%s" is deprecated and will be removed in version %d.0.',
  85305. self::SORT_LENGTH,
  85306. Application::getMajorVersion() + 1,
  85307. )));
  85308. }
  85309. return $value;
  85310. })
  85311. ->getOption(),
  85312. (new FixerOptionBuilder('imports_order', 'Defines the order of import types.'))
  85313. ->setAllowedTypes(['string[]', 'null'])
  85314. ->setAllowedValues([static function (?array $value) use ($supportedSortTypes): bool {
  85315. if (null !== $value) {
  85316. $missing = array_diff($supportedSortTypes, $value);
  85317. if (\count($missing) > 0) {
  85318. throw new InvalidOptionsException(\sprintf(
  85319. 'Missing sort %s %s.',
  85320. 1 === \count($missing) ? 'type' : 'types',
  85321. Utils::naturalLanguageJoin($missing)
  85322. ));
  85323. }
  85324. $unknown = array_diff($value, $supportedSortTypes);
  85325. if (\count($unknown) > 0) {
  85326. throw new InvalidOptionsException(\sprintf(
  85327. 'Unknown sort %s %s.',
  85328. 1 === \count($unknown) ? 'type' : 'types',
  85329. Utils::naturalLanguageJoin($unknown)
  85330. ));
  85331. }
  85332. }
  85333. return true;
  85334. }])
  85335. ->setDefault(null)
  85336. ->getOption(),
  85337. (new FixerOptionBuilder('case_sensitive', 'Whether the sorting should be case sensitive.'))
  85338. ->setAllowedTypes(['bool'])
  85339. ->setDefault(false)
  85340. ->getOption(),
  85341. ]);
  85342. }
  85343. private function sortAlphabetically(array $first, array $second): int
  85344. {
  85345. $firstNamespace = str_replace(['\\', '{'], [' ', ''], $this->prepareNamespace($first['namespace']));
  85346. $secondNamespace = str_replace(['\\', '{'], [' ', ''], $this->prepareNamespace($second['namespace']));
  85347. return true === $this->configuration['case_sensitive']
  85348. ? $firstNamespace <=> $secondNamespace
  85349. : strcasecmp($firstNamespace, $secondNamespace);
  85350. }
  85351. private function sortByLength(array $first, array $second): int
  85352. {
  85353. $firstNamespace = (self::IMPORT_TYPE_CLASS === $first['importType'] ? '' : $first['importType'].' ').$this->prepareNamespace($first['namespace']);
  85354. $secondNamespace = (self::IMPORT_TYPE_CLASS === $second['importType'] ? '' : $second['importType'].' ').$this->prepareNamespace($second['namespace']);
  85355. $firstNamespaceLength = \strlen($firstNamespace);
  85356. $secondNamespaceLength = \strlen($secondNamespace);
  85357. if ($firstNamespaceLength === $secondNamespaceLength) {
  85358. $sortResult = true === $this->configuration['case_sensitive']
  85359. ? $firstNamespace <=> $secondNamespace
  85360. : strcasecmp($firstNamespace, $secondNamespace);
  85361. } else {
  85362. $sortResult = $firstNamespaceLength > $secondNamespaceLength ? 1 : -1;
  85363. }
  85364. return $sortResult;
  85365. }
  85366. private function prepareNamespace(string $namespace): string
  85367. {
  85368. return trim(Preg::replace('%/\*(.*)\*/%s', '', $namespace));
  85369. }
  85370. private function getNewOrder(array $uses, Tokens $tokens): array
  85371. {
  85372. $indices = [];
  85373. $originalIndices = [];
  85374. $lineEnding = $this->whitespacesConfig->getLineEnding();
  85375. $usesCount = \count($uses);
  85376. for ($i = 0; $i < $usesCount; ++$i) {
  85377. $index = $uses[$i];
  85378. $startIndex = $tokens->getTokenNotOfKindsSibling($index + 1, 1, [T_WHITESPACE]);
  85379. $endIndex = $tokens->getNextTokenOfKind($startIndex, [';', [T_CLOSE_TAG]]);
  85380. $previous = $tokens->getPrevMeaningfulToken($endIndex);
  85381. $group = $tokens[$previous]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE);
  85382. if ($tokens[$startIndex]->isGivenKind(CT::T_CONST_IMPORT)) {
  85383. $type = self::IMPORT_TYPE_CONST;
  85384. $index = $tokens->getNextNonWhitespace($startIndex);
  85385. } elseif ($tokens[$startIndex]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  85386. $type = self::IMPORT_TYPE_FUNCTION;
  85387. $index = $tokens->getNextNonWhitespace($startIndex);
  85388. } else {
  85389. $type = self::IMPORT_TYPE_CLASS;
  85390. $index = $startIndex;
  85391. }
  85392. $namespaceTokens = [];
  85393. while ($index <= $endIndex) {
  85394. $token = $tokens[$index];
  85395. if ($index === $endIndex || (!$group && $token->equals(','))) {
  85396. if ($group && self::SORT_NONE !== $this->configuration['sort_algorithm']) {
  85397. $namespaceTokensCount = \count($namespaceTokens) - 1;
  85398. $namespace = '';
  85399. for ($k = 0; $k < $namespaceTokensCount; ++$k) {
  85400. if ($namespaceTokens[$k]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  85401. $namespace .= '{';
  85402. break;
  85403. }
  85404. $namespace .= $namespaceTokens[$k]->getContent();
  85405. }
  85406. $parts = [];
  85407. $firstIndent = '';
  85408. $separator = ', ';
  85409. $lastIndent = '';
  85410. $hasGroupTrailingComma = false;
  85411. for ($k1 = $k + 1; $k1 < $namespaceTokensCount; ++$k1) {
  85412. $comment = '';
  85413. $namespacePart = '';
  85414. for ($k2 = $k1;; ++$k2) {
  85415. if ($namespaceTokens[$k2]->equalsAny([',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]])) {
  85416. break;
  85417. }
  85418. if ($namespaceTokens[$k2]->isComment()) {
  85419. $comment .= $namespaceTokens[$k2]->getContent();
  85420. continue;
  85421. }
  85422. if (
  85423. '' === $firstIndent
  85424. && $namespaceTokens[$k2]->isWhitespace()
  85425. && str_contains($namespaceTokens[$k2]->getContent(), $lineEnding)
  85426. ) {
  85427. $lastIndent = $lineEnding;
  85428. $firstIndent = $lineEnding.$this->whitespacesConfig->getIndent();
  85429. $separator = ','.$firstIndent;
  85430. }
  85431. $namespacePart .= $namespaceTokens[$k2]->getContent();
  85432. }
  85433. $namespacePart = trim($namespacePart);
  85434. if ('' === $namespacePart) {
  85435. $hasGroupTrailingComma = true;
  85436. continue;
  85437. }
  85438. $comment = trim($comment);
  85439. if ('' !== $comment) {
  85440. $namespacePart .= ' '.$comment;
  85441. }
  85442. $parts[] = $namespacePart;
  85443. $k1 = $k2;
  85444. }
  85445. $sortedParts = $parts;
  85446. sort($parts);
  85447. if ($sortedParts === $parts) {
  85448. $namespace = Tokens::fromArray($namespaceTokens)->generateCode();
  85449. } else {
  85450. $namespace .= $firstIndent.implode($separator, $parts).($hasGroupTrailingComma ? ',' : '').$lastIndent.'}';
  85451. }
  85452. } else {
  85453. $namespace = Tokens::fromArray($namespaceTokens)->generateCode();
  85454. }
  85455. $indices[$startIndex] = [
  85456. 'namespace' => $namespace,
  85457. 'startIndex' => $startIndex,
  85458. 'endIndex' => $index - 1,
  85459. 'importType' => $type,
  85460. 'group' => $group,
  85461. ];
  85462. $originalIndices[] = $startIndex;
  85463. if ($index === $endIndex) {
  85464. break;
  85465. }
  85466. $namespaceTokens = [];
  85467. $nextPartIndex = $tokens->getTokenNotOfKindSibling($index, 1, [',', [T_WHITESPACE]]);
  85468. $startIndex = $nextPartIndex;
  85469. $index = $nextPartIndex;
  85470. continue;
  85471. }
  85472. $namespaceTokens[] = $token;
  85473. ++$index;
  85474. }
  85475. }
  85476. if (null !== $this->configuration['imports_order']) {
  85477. $groupedByTypes = [];
  85478. foreach ($indices as $startIndex => $item) {
  85479. $groupedByTypes[$item['importType']][$startIndex] = $item;
  85480. }
  85481. foreach ($groupedByTypes as $type => $groupIndices) {
  85482. $groupedByTypes[$type] = $this->sortByAlgorithm($groupIndices);
  85483. }
  85484. $sortedGroups = [];
  85485. foreach ($this->configuration['imports_order'] as $type) {
  85486. if (isset($groupedByTypes[$type]) && [] !== $groupedByTypes[$type]) {
  85487. foreach ($groupedByTypes[$type] as $startIndex => $item) {
  85488. $sortedGroups[$startIndex] = $item;
  85489. }
  85490. }
  85491. }
  85492. $indices = $sortedGroups;
  85493. } else {
  85494. $indices = $this->sortByAlgorithm($indices);
  85495. }
  85496. $index = -1;
  85497. $usesOrder = [];
  85498. foreach ($indices as $v) {
  85499. $usesOrder[$originalIndices[++$index]] = $v;
  85500. }
  85501. return $usesOrder;
  85502. }
  85503. private function sortByAlgorithm(array $indices): array
  85504. {
  85505. if (self::SORT_ALPHA === $this->configuration['sort_algorithm']) {
  85506. uasort($indices, [$this, 'sortAlphabetically']);
  85507. } elseif (self::SORT_LENGTH === $this->configuration['sort_algorithm']) {
  85508. uasort($indices, [$this, 'sortByLength']);
  85509. }
  85510. return $indices;
  85511. }
  85512. private function setNewOrder(Tokens $tokens, array $usesOrder): void
  85513. {
  85514. $mapStartToEnd = [];
  85515. foreach ($usesOrder as $use) {
  85516. $mapStartToEnd[$use['startIndex']] = $use['endIndex'];
  85517. }
  85518. foreach (array_reverse($usesOrder, true) as $index => $use) {
  85519. $code = \sprintf(
  85520. '<?php use %s%s;',
  85521. self::IMPORT_TYPE_CLASS === $use['importType'] ? '' : ' '.$use['importType'].' ',
  85522. $use['namespace']
  85523. );
  85524. $numberOfInitialTokensToClear = 3;
  85525. if (self::IMPORT_TYPE_CLASS !== $use['importType']) {
  85526. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  85527. if ($tokens[$prevIndex]->equals(',')) {
  85528. $numberOfInitialTokensToClear = 5;
  85529. }
  85530. }
  85531. $declarationTokens = Tokens::fromCode($code);
  85532. $declarationTokens->clearRange(0, $numberOfInitialTokensToClear - 1);
  85533. $declarationTokens->clearAt(\count($declarationTokens) - 1);
  85534. $declarationTokens->clearEmptyTokens();
  85535. $tokens->overrideRange($index, $mapStartToEnd[$index], $declarationTokens);
  85536. if ($use['group']) {
  85537. self::fixCommaToUse($tokens, $tokens->getPrevMeaningfulToken($index));
  85538. $closeGroupIndex = $tokens->getNextTokenOfKind($index, [[CT::T_GROUP_IMPORT_BRACE_CLOSE]]);
  85539. self::fixCommaToUse($tokens, $tokens->getNextMeaningfulToken($closeGroupIndex));
  85540. }
  85541. }
  85542. }
  85543. private static function fixCommaToUse(Tokens $tokens, int $index): void
  85544. {
  85545. if (!$tokens[$index]->equals(',')) {
  85546. return;
  85547. }
  85548. $tokens[$index] = new Token(';');
  85549. $tokens->insertAt($index + 1, new Token([T_USE, 'use']));
  85550. if (!$tokens[$index + 2]->isWhitespace()) {
  85551. $tokens->insertAt($index + 2, new Token([T_WHITESPACE, ' ']));
  85552. }
  85553. }
  85554. }
  85555. <?php
  85556. declare(strict_types=1);
  85557. namespace PhpCsFixer\Fixer\Import;
  85558. use PhpCsFixer\AbstractFixer;
  85559. use PhpCsFixer\FixerDefinition\CodeSample;
  85560. use PhpCsFixer\FixerDefinition\FixerDefinition;
  85561. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  85562. use PhpCsFixer\Tokenizer\CT;
  85563. use PhpCsFixer\Tokenizer\Tokens;
  85564. final class NoUnneededImportAliasFixer extends AbstractFixer
  85565. {
  85566. public function getDefinition(): FixerDefinitionInterface
  85567. {
  85568. return new FixerDefinition(
  85569. 'Imports should not be aliased as the same name.',
  85570. [new CodeSample("<?php\nuse A\\B\\Foo as Foo;\n")]
  85571. );
  85572. }
  85573. public function isCandidate(Tokens $tokens): bool
  85574. {
  85575. return $tokens->isAllTokenKindsFound([T_USE, T_AS]);
  85576. }
  85577. public function getPriority(): int
  85578. {
  85579. return 1;
  85580. }
  85581. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  85582. {
  85583. for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
  85584. if (!$tokens[$index]->isGivenKind(T_AS)) {
  85585. continue;
  85586. }
  85587. $aliasIndex = $tokens->getNextMeaningfulToken($index);
  85588. if (!$tokens[$aliasIndex]->isGivenKind(T_STRING)) {
  85589. continue;
  85590. }
  85591. $importIndex = $tokens->getPrevMeaningfulToken($index);
  85592. if (!$tokens[$importIndex]->isGivenKind(T_STRING)) {
  85593. continue;
  85594. }
  85595. if ($tokens[$importIndex]->getContent() !== $tokens[$aliasIndex]->getContent()) {
  85596. continue;
  85597. }
  85598. do {
  85599. $importIndex = $tokens->getPrevMeaningfulToken($importIndex);
  85600. } while ($tokens[$importIndex]->isGivenKind([T_NS_SEPARATOR, T_STRING, T_AS]) || $tokens[$importIndex]->equals(','));
  85601. if ($tokens[$importIndex]->isGivenKind([CT::T_FUNCTION_IMPORT, CT::T_CONST_IMPORT])) {
  85602. $importIndex = $tokens->getPrevMeaningfulToken($importIndex);
  85603. }
  85604. if (!$tokens[$importIndex]->isGivenKind([T_USE, CT::T_GROUP_IMPORT_BRACE_OPEN])) {
  85605. continue;
  85606. }
  85607. $tokens->clearTokenAndMergeSurroundingWhitespace($aliasIndex);
  85608. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  85609. }
  85610. }
  85611. }
  85612. <?php
  85613. declare(strict_types=1);
  85614. namespace PhpCsFixer\Fixer\Import;
  85615. use PhpCsFixer\AbstractFixer;
  85616. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  85617. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  85618. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  85619. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  85620. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  85621. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  85622. use PhpCsFixer\FixerDefinition\CodeSample;
  85623. use PhpCsFixer\FixerDefinition\FixerDefinition;
  85624. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  85625. use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
  85626. use PhpCsFixer\Tokenizer\CT;
  85627. use PhpCsFixer\Tokenizer\Token;
  85628. use PhpCsFixer\Tokenizer\Tokens;
  85629. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  85630. /**
  85631. @phpstan-type
  85632. @phpstan-type
  85633. @implements
  85634. */
  85635. final class SingleImportPerStatementFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
  85636. {
  85637. /**
  85638. @use */
  85639. use ConfigurableFixerTrait;
  85640. public function getDefinition(): FixerDefinitionInterface
  85641. {
  85642. return new FixerDefinition(
  85643. 'There MUST be one use keyword per declaration.',
  85644. [
  85645. new CodeSample(
  85646. '<?php
  85647. use Foo, Sample, Sample\Sample as Sample2;
  85648. '
  85649. ),
  85650. new CodeSample(
  85651. '<?php
  85652. use Space\Models\ {
  85653. TestModelA,
  85654. TestModelB,
  85655. TestModel,
  85656. };
  85657. ',
  85658. ['group_to_single_imports' => true]
  85659. ),
  85660. ]
  85661. );
  85662. }
  85663. public function getPriority(): int
  85664. {
  85665. return 1;
  85666. }
  85667. public function isCandidate(Tokens $tokens): bool
  85668. {
  85669. return $tokens->isTokenKindFound(T_USE);
  85670. }
  85671. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  85672. {
  85673. $tokensAnalyzer = new TokensAnalyzer($tokens);
  85674. foreach (array_reverse($tokensAnalyzer->getImportUseIndexes()) as $index) {
  85675. $endIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  85676. $groupClose = $tokens->getPrevMeaningfulToken($endIndex);
  85677. if ($tokens[$groupClose]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  85678. if (true === $this->configuration['group_to_single_imports']) {
  85679. $this->fixGroupUse($tokens, $index, $endIndex);
  85680. }
  85681. } else {
  85682. $this->fixMultipleUse($tokens, $index, $endIndex);
  85683. }
  85684. }
  85685. }
  85686. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  85687. {
  85688. return new FixerConfigurationResolver([
  85689. (new FixerOptionBuilder('group_to_single_imports', 'Whether to change group imports into single imports.'))
  85690. ->setAllowedTypes(['bool'])
  85691. ->setDefault(true)
  85692. ->getOption(),
  85693. ]);
  85694. }
  85695. private function getGroupDeclaration(Tokens $tokens, int $index): array
  85696. {
  85697. $groupPrefix = '';
  85698. $comment = '';
  85699. $groupOpenIndex = null;
  85700. for ($i = $index + 1;; ++$i) {
  85701. if ($tokens[$i]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  85702. $groupOpenIndex = $i;
  85703. break;
  85704. }
  85705. if ($tokens[$i]->isComment()) {
  85706. $comment .= $tokens[$i]->getContent();
  85707. if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i + 1]->isWhitespace()) {
  85708. $groupPrefix .= ' ';
  85709. }
  85710. continue;
  85711. }
  85712. if ($tokens[$i]->isWhitespace()) {
  85713. $groupPrefix .= ' ';
  85714. continue;
  85715. }
  85716. $groupPrefix .= $tokens[$i]->getContent();
  85717. }
  85718. return [
  85719. rtrim($groupPrefix),
  85720. $groupOpenIndex,
  85721. $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $groupOpenIndex),
  85722. $comment,
  85723. ];
  85724. }
  85725. private function getGroupStatements(Tokens $tokens, string $groupPrefix, int $groupOpenIndex, int $groupCloseIndex, string $comment): array
  85726. {
  85727. $statements = [];
  85728. $statement = $groupPrefix;
  85729. for ($i = $groupOpenIndex + 1; $i <= $groupCloseIndex; ++$i) {
  85730. $token = $tokens[$i];
  85731. if ($token->equals(',') && $tokens[$tokens->getNextMeaningfulToken($i)]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  85732. continue;
  85733. }
  85734. if ($token->equalsAny([',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]])) {
  85735. $statements[] = 'use'.$statement.';';
  85736. $statement = $groupPrefix;
  85737. continue;
  85738. }
  85739. if ($token->isWhitespace()) {
  85740. $j = $tokens->getNextMeaningfulToken($i);
  85741. if ($tokens[$j]->isGivenKind(T_AS)) {
  85742. $statement .= ' as ';
  85743. $i += 2;
  85744. } elseif ($tokens[$j]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  85745. $statement = ' function'.$statement;
  85746. $i += 2;
  85747. } elseif ($tokens[$j]->isGivenKind(CT::T_CONST_IMPORT)) {
  85748. $statement = ' const'.$statement;
  85749. $i += 2;
  85750. }
  85751. if ($token->isWhitespace(" \t") || !str_starts_with($tokens[$i - 1]->getContent(), '//')) {
  85752. continue;
  85753. }
  85754. }
  85755. $statement .= $token->getContent();
  85756. }
  85757. if ('' !== $comment) {
  85758. $statements[0] .= ' '.$comment;
  85759. }
  85760. return $statements;
  85761. }
  85762. private function fixGroupUse(Tokens $tokens, int $index, int $endIndex): void
  85763. {
  85764. [$groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment] = $this->getGroupDeclaration($tokens, $index);
  85765. $statements = $this->getGroupStatements($tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment);
  85766. $tokens->clearRange($index, $groupCloseIndex);
  85767. if ($tokens[$endIndex]->equals(';')) {
  85768. $tokens->clearAt($endIndex);
  85769. }
  85770. $ending = $this->whitespacesConfig->getLineEnding();
  85771. $importTokens = Tokens::fromCode('<?php '.implode($ending, $statements));
  85772. $importTokens->clearAt(0);
  85773. $importTokens->clearEmptyTokens();
  85774. $tokens->insertAt($index, $importTokens);
  85775. }
  85776. private function fixMultipleUse(Tokens $tokens, int $index, int $endIndex): void
  85777. {
  85778. $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
  85779. if ($tokens[$nextTokenIndex]->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  85780. $leadingTokens = [
  85781. new Token([CT::T_FUNCTION_IMPORT, 'function']),
  85782. new Token([T_WHITESPACE, ' ']),
  85783. ];
  85784. } elseif ($tokens[$nextTokenIndex]->isGivenKind(CT::T_CONST_IMPORT)) {
  85785. $leadingTokens = [
  85786. new Token([CT::T_CONST_IMPORT, 'const']),
  85787. new Token([T_WHITESPACE, ' ']),
  85788. ];
  85789. } else {
  85790. $leadingTokens = [];
  85791. }
  85792. $ending = $this->whitespacesConfig->getLineEnding();
  85793. for ($i = $endIndex - 1; $i > $index; --$i) {
  85794. if (!$tokens[$i]->equals(',')) {
  85795. continue;
  85796. }
  85797. $tokens[$i] = new Token(';');
  85798. $i = $tokens->getNextMeaningfulToken($i);
  85799. $tokens->insertAt($i, new Token([T_USE, 'use']));
  85800. $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
  85801. foreach ($leadingTokens as $offset => $leadingToken) {
  85802. $tokens->insertAt($i + 2 + $offset, clone $leadingToken);
  85803. }
  85804. $indent = WhitespacesAnalyzer::detectIndent($tokens, $index);
  85805. if ($tokens[$i - 1]->isWhitespace()) {
  85806. $tokens[$i - 1] = new Token([T_WHITESPACE, $ending.$indent]);
  85807. } elseif (!str_contains($tokens[$i - 1]->getContent(), "\n")) {
  85808. $tokens->insertAt($i, new Token([T_WHITESPACE, $ending.$indent]));
  85809. }
  85810. }
  85811. }
  85812. }
  85813. <?php
  85814. declare(strict_types=1);
  85815. namespace PhpCsFixer\Fixer\Import;
  85816. use PhpCsFixer\AbstractFixer;
  85817. use PhpCsFixer\FixerDefinition\CodeSample;
  85818. use PhpCsFixer\FixerDefinition\FixerDefinition;
  85819. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  85820. use PhpCsFixer\Tokenizer\CT;
  85821. use PhpCsFixer\Tokenizer\Token;
  85822. use PhpCsFixer\Tokenizer\Tokens;
  85823. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  85824. final class NoLeadingImportSlashFixer extends AbstractFixer
  85825. {
  85826. public function getDefinition(): FixerDefinitionInterface
  85827. {
  85828. return new FixerDefinition(
  85829. 'Remove leading slashes in `use` clauses.',
  85830. [new CodeSample("<?php\nnamespace Foo;\nuse \\Bar;\n")]
  85831. );
  85832. }
  85833. public function getPriority(): int
  85834. {
  85835. return -20;
  85836. }
  85837. public function isCandidate(Tokens $tokens): bool
  85838. {
  85839. return $tokens->isTokenKindFound(T_USE);
  85840. }
  85841. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  85842. {
  85843. $tokensAnalyzer = new TokensAnalyzer($tokens);
  85844. $usesIndices = $tokensAnalyzer->getImportUseIndexes();
  85845. foreach ($usesIndices as $idx) {
  85846. $nextTokenIdx = $tokens->getNextMeaningfulToken($idx);
  85847. $nextToken = $tokens[$nextTokenIdx];
  85848. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  85849. $this->removeLeadingImportSlash($tokens, $nextTokenIdx);
  85850. } elseif ($nextToken->isGivenKind([CT::T_FUNCTION_IMPORT, CT::T_CONST_IMPORT])) {
  85851. $nextTokenIdx = $tokens->getNextMeaningfulToken($nextTokenIdx);
  85852. if ($tokens[$nextTokenIdx]->isGivenKind(T_NS_SEPARATOR)) {
  85853. $this->removeLeadingImportSlash($tokens, $nextTokenIdx);
  85854. }
  85855. }
  85856. }
  85857. }
  85858. private function removeLeadingImportSlash(Tokens $tokens, int $index): void
  85859. {
  85860. $previousIndex = $tokens->getPrevNonWhitespace($index);
  85861. if (
  85862. $previousIndex < $index - 1
  85863. || $tokens[$previousIndex]->isComment()
  85864. ) {
  85865. $tokens->clearAt($index);
  85866. return;
  85867. }
  85868. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  85869. }
  85870. }
  85871. <?php
  85872. declare(strict_types=1);
  85873. namespace PhpCsFixer\Fixer\Import;
  85874. use PhpCsFixer\AbstractFixer;
  85875. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  85876. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  85877. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  85878. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  85879. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  85880. use PhpCsFixer\FixerDefinition\CodeSample;
  85881. use PhpCsFixer\FixerDefinition\FixerDefinition;
  85882. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  85883. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  85884. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  85885. use PhpCsFixer\Tokenizer\CT;
  85886. use PhpCsFixer\Tokenizer\Token;
  85887. use PhpCsFixer\Tokenizer\Tokens;
  85888. use PhpCsFixer\Utils;
  85889. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  85890. /**
  85891. @phpstan-type
  85892. @phpstan-type
  85893. @implements
  85894. */
  85895. final class GroupImportFixer extends AbstractFixer implements ConfigurableFixerInterface
  85896. {
  85897. /**
  85898. @use */
  85899. use ConfigurableFixerTrait;
  85900. public const GROUP_CLASSY = 'classy';
  85901. public const GROUP_CONSTANTS = 'constants';
  85902. public const GROUP_FUNCTIONS = 'functions';
  85903. public function getDefinition(): FixerDefinitionInterface
  85904. {
  85905. return new FixerDefinition(
  85906. 'There MUST be group use for the same namespaces.',
  85907. [
  85908. new CodeSample(
  85909. "<?php\nuse Foo\\Bar;\nuse Foo\\Baz;\n"
  85910. ),
  85911. new CodeSample(
  85912. <<<'PHP'
  85913. <?php
  85914. use A\Foo;
  85915. use function B\foo;
  85916. use A\Bar;
  85917. use function B\bar;
  85918. PHP,
  85919. ['group_types' => [self::GROUP_CLASSY]]
  85920. ),
  85921. ]
  85922. );
  85923. }
  85924. public function isCandidate(Tokens $tokens): bool
  85925. {
  85926. return $tokens->isTokenKindFound(T_USE);
  85927. }
  85928. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  85929. {
  85930. $allowedTypes = [self::GROUP_CLASSY, self::GROUP_FUNCTIONS, self::GROUP_CONSTANTS];
  85931. return new FixerConfigurationResolver([
  85932. (new FixerOptionBuilder('group_types', 'Defines the order of import types.'))
  85933. ->setAllowedTypes(['string[]'])
  85934. ->setAllowedValues([static function (array $types) use ($allowedTypes): bool {
  85935. foreach ($types as $type) {
  85936. if (!\in_array($type, $allowedTypes, true)) {
  85937. throw new InvalidOptionsException(
  85938. \sprintf(
  85939. 'Invalid group type: %s, allowed types: %s.',
  85940. $type,
  85941. Utils::naturalLanguageJoin($allowedTypes)
  85942. )
  85943. );
  85944. }
  85945. }
  85946. return true;
  85947. }])
  85948. ->setDefault($allowedTypes)
  85949. ->getOption(),
  85950. ]);
  85951. }
  85952. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  85953. {
  85954. $useWithSameNamespaces = $this->getSameNamespacesByType($tokens);
  85955. if ([] === $useWithSameNamespaces) {
  85956. return;
  85957. }
  85958. $typeMap = [
  85959. NamespaceUseAnalysis::TYPE_CLASS => self::GROUP_CLASSY,
  85960. NamespaceUseAnalysis::TYPE_FUNCTION => self::GROUP_FUNCTIONS,
  85961. NamespaceUseAnalysis::TYPE_CONSTANT => self::GROUP_CONSTANTS,
  85962. ];
  85963. foreach ($useWithSameNamespaces as $type => $uses) {
  85964. if (!\in_array($typeMap[$type], $this->configuration['group_types'], true)) {
  85965. continue;
  85966. }
  85967. $this->removeSingleUseStatements($uses, $tokens);
  85968. }
  85969. foreach ($useWithSameNamespaces as $type => $uses) {
  85970. if (!\in_array($typeMap[$type], $this->configuration['group_types'], true)) {
  85971. continue;
  85972. }
  85973. $this->addGroupUseStatements($uses, $tokens);
  85974. }
  85975. }
  85976. private function getSameNamespacesByType(Tokens $tokens): array
  85977. {
  85978. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  85979. if (0 === \count($useDeclarations)) {
  85980. return [];
  85981. }
  85982. $allNamespaceAndType = array_map(
  85983. fn (NamespaceUseAnalysis $useDeclaration): string => $this->getNamespaceNameWithSlash($useDeclaration).$useDeclaration->getType(),
  85984. $useDeclarations
  85985. );
  85986. $sameNamespaces = array_filter(array_count_values($allNamespaceAndType), static fn (int $count): bool => $count > 1);
  85987. $sameNamespaces = array_keys($sameNamespaces);
  85988. $sameNamespaceAnalysis = array_filter($useDeclarations, function (NamespaceUseAnalysis $useDeclaration) use ($sameNamespaces): bool {
  85989. $namespaceNameAndType = $this->getNamespaceNameWithSlash($useDeclaration).$useDeclaration->getType();
  85990. return \in_array($namespaceNameAndType, $sameNamespaces, true);
  85991. });
  85992. usort($sameNamespaceAnalysis, function (NamespaceUseAnalysis $a, NamespaceUseAnalysis $b): int {
  85993. $namespaceA = $this->getNamespaceNameWithSlash($a);
  85994. $namespaceB = $this->getNamespaceNameWithSlash($b);
  85995. $namespaceDifference = \strlen($namespaceA) <=> \strlen($namespaceB);
  85996. return 0 !== $namespaceDifference ? $namespaceDifference : $a->getFullName() <=> $b->getFullName();
  85997. });
  85998. $sameNamespaceAnalysisByType = [];
  85999. foreach ($sameNamespaceAnalysis as $analysis) {
  86000. $sameNamespaceAnalysisByType[$analysis->getType()][] = $analysis;
  86001. }
  86002. ksort($sameNamespaceAnalysisByType);
  86003. return $sameNamespaceAnalysisByType;
  86004. }
  86005. private function removeSingleUseStatements(array $statements, Tokens $tokens): void
  86006. {
  86007. foreach ($statements as $useDeclaration) {
  86008. $index = $useDeclaration->getStartIndex();
  86009. $endIndex = $useDeclaration->getEndIndex();
  86010. $useStatementTokens = [T_USE, T_WHITESPACE, T_STRING, T_NS_SEPARATOR, T_AS, CT::T_CONST_IMPORT, CT::T_FUNCTION_IMPORT];
  86011. while ($index !== $endIndex) {
  86012. if ($tokens[$index]->isGivenKind($useStatementTokens)) {
  86013. $tokens->clearAt($index);
  86014. }
  86015. ++$index;
  86016. }
  86017. if (isset($tokens[$index]) && $tokens[$index]->equals(';')) {
  86018. $tokens->clearAt($index);
  86019. }
  86020. ++$index;
  86021. if (isset($tokens[$index]) && $tokens[$index]->isGivenKind(T_WHITESPACE)) {
  86022. $tokens->clearAt($index);
  86023. }
  86024. }
  86025. }
  86026. private function addGroupUseStatements(array $statements, Tokens $tokens): void
  86027. {
  86028. $currentUseDeclaration = null;
  86029. $insertIndex = $statements[0]->getStartIndex();
  86030. if (null !== $tokens[$insertIndex]->getId() || '' !== $tokens[$insertIndex]->getContent()) {
  86031. do {
  86032. ++$insertIndex;
  86033. } while (null !== $tokens[$insertIndex]->getId() || '' !== $tokens[$insertIndex]->getContent());
  86034. }
  86035. foreach ($statements as $index => $useDeclaration) {
  86036. if ($this->areDeclarationsDifferent($currentUseDeclaration, $useDeclaration)) {
  86037. $currentUseDeclaration = $useDeclaration;
  86038. $insertIndex += $this->createNewGroup(
  86039. $tokens,
  86040. $insertIndex,
  86041. $useDeclaration,
  86042. rtrim($this->getNamespaceNameWithSlash($currentUseDeclaration), '\\')
  86043. );
  86044. } else {
  86045. $newTokens = [
  86046. new Token(','),
  86047. new Token([T_WHITESPACE, ' ']),
  86048. ];
  86049. if ($useDeclaration->isAliased()) {
  86050. $tokens->insertAt($insertIndex, $newTokens);
  86051. $insertIndex += \count($newTokens);
  86052. $newTokens = [];
  86053. $insertIndex += $this->insertToGroupUseWithAlias($tokens, $insertIndex, $useDeclaration);
  86054. }
  86055. $newTokens[] = new Token([T_STRING, $useDeclaration->getShortName()]);
  86056. if (!isset($statements[$index + 1]) || $this->areDeclarationsDifferent($currentUseDeclaration, $statements[$index + 1])) {
  86057. $newTokens[] = new Token([CT::T_GROUP_IMPORT_BRACE_CLOSE, '}']);
  86058. $newTokens[] = new Token(';');
  86059. $newTokens[] = new Token([T_WHITESPACE, "\n"]);
  86060. }
  86061. $tokens->insertAt($insertIndex, $newTokens);
  86062. $insertIndex += \count($newTokens);
  86063. }
  86064. }
  86065. }
  86066. private function getNamespaceNameWithSlash(NamespaceUseAnalysis $useDeclaration): string
  86067. {
  86068. $position = strrpos($useDeclaration->getFullName(), '\\');
  86069. if (false === $position || 0 === $position) {
  86070. return $useDeclaration->getFullName();
  86071. }
  86072. return substr($useDeclaration->getFullName(), 0, $position + 1);
  86073. }
  86074. private function insertToGroupUseWithAlias(Tokens $tokens, int $insertIndex, NamespaceUseAnalysis $useDeclaration): int
  86075. {
  86076. $newTokens = [
  86077. new Token([T_STRING, substr($useDeclaration->getFullName(), strripos($useDeclaration->getFullName(), '\\') + 1)]),
  86078. new Token([T_WHITESPACE, ' ']),
  86079. new Token([T_AS, 'as']),
  86080. new Token([T_WHITESPACE, ' ']),
  86081. ];
  86082. $tokens->insertAt($insertIndex, $newTokens);
  86083. return \count($newTokens);
  86084. }
  86085. private function createNewGroup(Tokens $tokens, int $insertIndex, NamespaceUseAnalysis $useDeclaration, string $currentNamespace): int
  86086. {
  86087. $insertedTokens = 0;
  86088. $newTokens = [
  86089. new Token([T_USE, 'use']),
  86090. new Token([T_WHITESPACE, ' ']),
  86091. ];
  86092. if ($useDeclaration->isFunction() || $useDeclaration->isConstant()) {
  86093. $importStatementParams = $useDeclaration->isFunction()
  86094. ? [CT::T_FUNCTION_IMPORT, 'function']
  86095. : [CT::T_CONST_IMPORT, 'const'];
  86096. $newTokens[] = new Token($importStatementParams);
  86097. $newTokens[] = new Token([T_WHITESPACE, ' ']);
  86098. }
  86099. $namespaceParts = explode('\\', $currentNamespace);
  86100. foreach ($namespaceParts as $part) {
  86101. $newTokens[] = new Token([T_STRING, $part]);
  86102. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  86103. }
  86104. $newTokens[] = new Token([CT::T_GROUP_IMPORT_BRACE_OPEN, '{']);
  86105. $newTokensCount = \count($newTokens);
  86106. $tokens->insertAt($insertIndex, $newTokens);
  86107. $insertedTokens += $newTokensCount;
  86108. $insertIndex += $newTokensCount;
  86109. if ($useDeclaration->isAliased()) {
  86110. $inserted = $this->insertToGroupUseWithAlias($tokens, $insertIndex + 1, $useDeclaration) + 1;
  86111. $insertedTokens += $inserted;
  86112. $insertIndex += $inserted;
  86113. }
  86114. $tokens->insertAt($insertIndex, new Token([T_STRING, $useDeclaration->getShortName()]));
  86115. return ++$insertedTokens;
  86116. }
  86117. private function areDeclarationsDifferent(?NamespaceUseAnalysis $analysis1, ?NamespaceUseAnalysis $analysis2): bool
  86118. {
  86119. if (null === $analysis1 || null === $analysis2) {
  86120. return true;
  86121. }
  86122. $namespaceName1 = $this->getNamespaceNameWithSlash($analysis1);
  86123. $namespaceName2 = $this->getNamespaceNameWithSlash($analysis2);
  86124. return $namespaceName1 !== $namespaceName2 || $analysis1->getType() !== $analysis2->getType();
  86125. }
  86126. }
  86127. <?php
  86128. declare(strict_types=1);
  86129. namespace PhpCsFixer\Fixer\Import;
  86130. use PhpCsFixer\AbstractFixer;
  86131. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  86132. use PhpCsFixer\FixerDefinition\CodeSample;
  86133. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86134. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86135. use PhpCsFixer\Tokenizer\Token;
  86136. use PhpCsFixer\Tokenizer\Tokens;
  86137. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  86138. use PhpCsFixer\Utils;
  86139. final class SingleLineAfterImportsFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  86140. {
  86141. public function isCandidate(Tokens $tokens): bool
  86142. {
  86143. return $tokens->isTokenKindFound(T_USE);
  86144. }
  86145. public function getDefinition(): FixerDefinitionInterface
  86146. {
  86147. return new FixerDefinition(
  86148. 'Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block.',
  86149. [
  86150. new CodeSample(
  86151. '<?php
  86152. namespace Foo;
  86153. use Bar;
  86154. use Baz;
  86155. final class Example
  86156. {
  86157. }
  86158. '
  86159. ),
  86160. new CodeSample(
  86161. '<?php
  86162. namespace Foo;
  86163. use Bar;
  86164. use Baz;
  86165. final class Example
  86166. {
  86167. }
  86168. '
  86169. ),
  86170. ]
  86171. );
  86172. }
  86173. public function getPriority(): int
  86174. {
  86175. return -11;
  86176. }
  86177. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86178. {
  86179. $ending = $this->whitespacesConfig->getLineEnding();
  86180. $tokensAnalyzer = new TokensAnalyzer($tokens);
  86181. $added = 0;
  86182. foreach ($tokensAnalyzer->getImportUseIndexes() as $index) {
  86183. $index += $added;
  86184. $indent = '';
  86185. if ($tokens[$index - 1]->isWhitespace(" \t") && $tokens[$index - 2]->isGivenKind(T_COMMENT)) {
  86186. $indent = $tokens[$index - 1]->getContent();
  86187. } elseif ($tokens[$index - 1]->isWhitespace()) {
  86188. $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
  86189. }
  86190. $semicolonIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  86191. $insertIndex = $semicolonIndex;
  86192. if ($tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG)) {
  86193. if ($tokens[$insertIndex - 1]->isWhitespace()) {
  86194. --$insertIndex;
  86195. }
  86196. $tokens->insertAt($insertIndex, new Token(';'));
  86197. ++$added;
  86198. }
  86199. if ($semicolonIndex === \count($tokens) - 1) {
  86200. $tokens->insertAt($insertIndex + 1, new Token([T_WHITESPACE, $ending.$ending.$indent]));
  86201. ++$added;
  86202. } else {
  86203. $newline = $ending;
  86204. $tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG) ? --$insertIndex : ++$insertIndex;
  86205. if ($tokens[$insertIndex]->isWhitespace(" \t") && $tokens[$insertIndex + 1]->isComment()) {
  86206. ++$insertIndex;
  86207. }
  86208. if ($tokens[$insertIndex]->isComment()) {
  86209. ++$insertIndex;
  86210. }
  86211. $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
  86212. if (null === $afterSemicolon || !$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
  86213. $newline .= $ending;
  86214. }
  86215. if ($tokens[$insertIndex]->isWhitespace()) {
  86216. $nextToken = $tokens[$insertIndex];
  86217. if (2 === substr_count($nextToken->getContent(), "\n")) {
  86218. continue;
  86219. }
  86220. $nextMeaningfulAfterUseIndex = $tokens->getNextMeaningfulToken($insertIndex);
  86221. if (null !== $nextMeaningfulAfterUseIndex && $tokens[$nextMeaningfulAfterUseIndex]->isGivenKind(T_USE)) {
  86222. if (substr_count($nextToken->getContent(), "\n") < 1) {
  86223. $tokens[$insertIndex] = new Token([T_WHITESPACE, $newline.$indent.ltrim($nextToken->getContent())]);
  86224. }
  86225. } else {
  86226. $tokens[$insertIndex] = new Token([T_WHITESPACE, $newline.$indent.ltrim($nextToken->getContent())]);
  86227. }
  86228. } else {
  86229. $tokens->insertAt($insertIndex, new Token([T_WHITESPACE, $newline.$indent]));
  86230. ++$added;
  86231. }
  86232. }
  86233. }
  86234. }
  86235. }
  86236. <?php
  86237. declare(strict_types=1);
  86238. namespace PhpCsFixer\Fixer\ArrayNotation;
  86239. use PhpCsFixer\AbstractFixer;
  86240. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  86241. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  86242. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  86243. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  86244. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  86245. use PhpCsFixer\FixerDefinition\CodeSample;
  86246. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86247. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86248. use PhpCsFixer\Tokenizer\CT;
  86249. use PhpCsFixer\Tokenizer\Token;
  86250. use PhpCsFixer\Tokenizer\Tokens;
  86251. /**
  86252. @phpstan-type
  86253. @phpstan-type
  86254. @implements
  86255. */
  86256. final class ArraySyntaxFixer extends AbstractFixer implements ConfigurableFixerInterface
  86257. {
  86258. /**
  86259. @use */
  86260. use ConfigurableFixerTrait;
  86261. private $candidateTokenKind;
  86262. public function getDefinition(): FixerDefinitionInterface
  86263. {
  86264. return new FixerDefinition(
  86265. 'PHP arrays should be declared using the configured syntax.',
  86266. [
  86267. new CodeSample(
  86268. "<?php\narray(1,2);\n"
  86269. ),
  86270. new CodeSample(
  86271. "<?php\n[1,2];\n",
  86272. ['syntax' => 'long']
  86273. ),
  86274. ]
  86275. );
  86276. }
  86277. public function getPriority(): int
  86278. {
  86279. return 37;
  86280. }
  86281. public function isCandidate(Tokens $tokens): bool
  86282. {
  86283. return $tokens->isTokenKindFound($this->candidateTokenKind);
  86284. }
  86285. protected function configurePostNormalisation(): void
  86286. {
  86287. $this->resolveCandidateTokenKind();
  86288. }
  86289. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86290. {
  86291. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  86292. if ($tokens[$index]->isGivenKind($this->candidateTokenKind)) {
  86293. if ('short' === $this->configuration['syntax']) {
  86294. $this->fixToShortArraySyntax($tokens, $index);
  86295. } else {
  86296. $this->fixToLongArraySyntax($tokens, $index);
  86297. }
  86298. }
  86299. }
  86300. }
  86301. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  86302. {
  86303. return new FixerConfigurationResolver([
  86304. (new FixerOptionBuilder('syntax', 'Whether to use the `long` or `short` array syntax.'))
  86305. ->setAllowedValues(['long', 'short'])
  86306. ->setDefault('short')
  86307. ->getOption(),
  86308. ]);
  86309. }
  86310. private function fixToLongArraySyntax(Tokens $tokens, int $index): void
  86311. {
  86312. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  86313. $tokens[$index] = new Token('(');
  86314. $tokens[$closeIndex] = new Token(')');
  86315. $tokens->insertAt($index, new Token([T_ARRAY, 'array']));
  86316. }
  86317. private function fixToShortArraySyntax(Tokens $tokens, int $index): void
  86318. {
  86319. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  86320. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  86321. $tokens[$openIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
  86322. $tokens[$closeIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);
  86323. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  86324. }
  86325. private function resolveCandidateTokenKind(): void
  86326. {
  86327. $this->candidateTokenKind = 'long' === $this->configuration['syntax'] ? CT::T_ARRAY_SQUARE_BRACE_OPEN : T_ARRAY;
  86328. }
  86329. }
  86330. <?php
  86331. declare(strict_types=1);
  86332. namespace PhpCsFixer\Fixer\ArrayNotation;
  86333. use PhpCsFixer\AbstractFixer;
  86334. use PhpCsFixer\FixerDefinition\CodeSample;
  86335. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86336. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86337. use PhpCsFixer\Tokenizer\CT;
  86338. use PhpCsFixer\Tokenizer\Tokens;
  86339. final class TrimArraySpacesFixer extends AbstractFixer
  86340. {
  86341. public function getDefinition(): FixerDefinitionInterface
  86342. {
  86343. return new FixerDefinition(
  86344. 'Arrays should be formatted like function/method arguments, without leading or trailing single line space.',
  86345. [new CodeSample("<?php\n\$sample = array( );\n\$sample = array( 'a', 'b' );\n")]
  86346. );
  86347. }
  86348. public function isCandidate(Tokens $tokens): bool
  86349. {
  86350. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN]);
  86351. }
  86352. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86353. {
  86354. for ($index = 0, $c = $tokens->count(); $index < $c; ++$index) {
  86355. if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN])) {
  86356. self::fixArray($tokens, $index);
  86357. }
  86358. }
  86359. }
  86360. private static function fixArray(Tokens $tokens, int $index): void
  86361. {
  86362. $startIndex = $index;
  86363. if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) {
  86364. $startIndex = $tokens->getNextMeaningfulToken($startIndex);
  86365. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  86366. } elseif ($tokens[$startIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
  86367. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE, $startIndex);
  86368. } else {
  86369. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  86370. }
  86371. $nextIndex = $startIndex + 1;
  86372. $nextToken = $tokens[$nextIndex];
  86373. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($startIndex);
  86374. $nextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex];
  86375. $tokenAfterNextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex + 1];
  86376. $prevIndex = $endIndex - 1;
  86377. $prevToken = $tokens[$prevIndex];
  86378. $prevNonWhitespaceIndex = $tokens->getPrevNonWhitespace($endIndex);
  86379. $prevNonWhitespaceToken = $tokens[$prevNonWhitespaceIndex];
  86380. if (
  86381. $nextToken->isWhitespace(" \t")
  86382. && (
  86383. !$nextNonWhitespaceToken->isComment()
  86384. || $nextNonWhitespaceIndex === $prevNonWhitespaceIndex
  86385. || $tokenAfterNextNonWhitespaceToken->isWhitespace(" \t")
  86386. || str_starts_with($nextNonWhitespaceToken->getContent(), '/*')
  86387. )
  86388. ) {
  86389. $tokens->clearAt($nextIndex);
  86390. }
  86391. if (
  86392. $prevToken->isWhitespace(" \t")
  86393. && !$prevNonWhitespaceToken->equals(',')
  86394. ) {
  86395. $tokens->clearAt($prevIndex);
  86396. }
  86397. }
  86398. }
  86399. <?php
  86400. declare(strict_types=1);
  86401. namespace PhpCsFixer\Fixer\ArrayNotation;
  86402. use PhpCsFixer\AbstractFixer;
  86403. use PhpCsFixer\FixerDefinition\CodeSample;
  86404. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86405. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86406. use PhpCsFixer\Tokenizer\CT;
  86407. use PhpCsFixer\Tokenizer\Token;
  86408. use PhpCsFixer\Tokenizer\Tokens;
  86409. final class ReturnToYieldFromFixer extends AbstractFixer
  86410. {
  86411. public function getDefinition(): FixerDefinitionInterface
  86412. {
  86413. return new FixerDefinition(
  86414. 'If the function explicitly returns an array, and has the return type `iterable`, then `yield from` must be used instead of `return`.',
  86415. [new CodeSample('<?php function giveMeData(): iterable {
  86416. return [1, 2, 3];
  86417. }
  86418. ')],
  86419. );
  86420. }
  86421. public function isCandidate(Tokens $tokens): bool
  86422. {
  86423. return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN]) && $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  86424. }
  86425. public function getPriority(): int
  86426. {
  86427. return 1;
  86428. }
  86429. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86430. {
  86431. foreach ($tokens->findGivenKind(T_RETURN) as $index => $token) {
  86432. if (!$this->shouldBeFixed($tokens, $index)) {
  86433. continue;
  86434. }
  86435. $tokens[$index] = new Token([T_YIELD_FROM, 'yield from']);
  86436. }
  86437. }
  86438. private function shouldBeFixed(Tokens $tokens, int $returnIndex): bool
  86439. {
  86440. $arrayStartIndex = $tokens->getNextMeaningfulToken($returnIndex);
  86441. if (!$tokens[$arrayStartIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86442. return false;
  86443. }
  86444. if ($tokens[$arrayStartIndex]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  86445. $arrayEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $arrayStartIndex);
  86446. } else {
  86447. $arrayOpenParenthesisIndex = $tokens->getNextTokenOfKind($arrayStartIndex, ['(']);
  86448. $arrayEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $arrayOpenParenthesisIndex);
  86449. }
  86450. $functionEndIndex = $arrayEndIndex;
  86451. do {
  86452. $functionEndIndex = $tokens->getNextMeaningfulToken($functionEndIndex);
  86453. } while (null !== $functionEndIndex && $tokens[$functionEndIndex]->equals(';'));
  86454. if (null === $functionEndIndex || !$tokens[$functionEndIndex]->equals('}')) {
  86455. return false;
  86456. }
  86457. $functionStartIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $functionEndIndex);
  86458. $returnTypeIndex = $tokens->getPrevMeaningfulToken($functionStartIndex);
  86459. if (!$tokens[$returnTypeIndex]->isGivenKind(T_STRING)) {
  86460. return false;
  86461. }
  86462. if ('iterable' !== strtolower($tokens[$returnTypeIndex]->getContent())) {
  86463. return false;
  86464. }
  86465. $beforeReturnTypeIndex = $tokens->getPrevMeaningfulToken($returnTypeIndex);
  86466. return $tokens[$beforeReturnTypeIndex]->isGivenKind(CT::T_TYPE_COLON);
  86467. }
  86468. }
  86469. <?php
  86470. declare(strict_types=1);
  86471. namespace PhpCsFixer\Fixer\ArrayNotation;
  86472. use PhpCsFixer\AbstractFixer;
  86473. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  86474. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  86475. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  86476. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  86477. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  86478. use PhpCsFixer\FixerDefinition\CodeSample;
  86479. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86480. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86481. use PhpCsFixer\Tokenizer\CT;
  86482. use PhpCsFixer\Tokenizer\Tokens;
  86483. /**
  86484. @phpstan-type
  86485. @phpstan-type
  86486. @implements
  86487. */
  86488. final class NoWhitespaceBeforeCommaInArrayFixer extends AbstractFixer implements ConfigurableFixerInterface
  86489. {
  86490. /**
  86491. @use */
  86492. use ConfigurableFixerTrait;
  86493. public function getDefinition(): FixerDefinitionInterface
  86494. {
  86495. return new FixerDefinition(
  86496. 'In array declaration, there MUST NOT be a whitespace before each comma.',
  86497. [
  86498. new CodeSample("<?php \$x = array(1 , \"2\");\n"),
  86499. new CodeSample(
  86500. <<<'PHP'
  86501. <?php
  86502. $x = [<<<EOD
  86503. foo
  86504. EOD
  86505. , 'bar'
  86506. ];
  86507. PHP,
  86508. ['after_heredoc' => true]
  86509. ),
  86510. ]
  86511. );
  86512. }
  86513. public function isCandidate(Tokens $tokens): bool
  86514. {
  86515. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  86516. }
  86517. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86518. {
  86519. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  86520. if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86521. $this->fixSpacing($index, $tokens);
  86522. }
  86523. }
  86524. }
  86525. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  86526. {
  86527. return new FixerConfigurationResolver([
  86528. (new FixerOptionBuilder('after_heredoc', 'Whether the whitespace between heredoc end and comma should be removed.'))
  86529. ->setAllowedTypes(['bool'])
  86530. ->setDefault(false)
  86531. ->getOption(),
  86532. ]);
  86533. }
  86534. private function fixSpacing(int $index, Tokens $tokens): void
  86535. {
  86536. if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  86537. $startIndex = $index;
  86538. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  86539. } else {
  86540. $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
  86541. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  86542. }
  86543. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  86544. $i = $this->skipNonArrayElements($i, $tokens);
  86545. $currentToken = $tokens[$i];
  86546. $prevIndex = $tokens->getPrevNonWhitespace($i - 1);
  86547. if (
  86548. $currentToken->equals(',') && !$tokens[$prevIndex]->isComment()
  86549. && (true === $this->configuration['after_heredoc'] || !$tokens[$prevIndex]->isGivenKind(T_END_HEREDOC))
  86550. ) {
  86551. $tokens->removeLeadingWhitespace($i);
  86552. }
  86553. }
  86554. }
  86555. private function skipNonArrayElements(int $index, Tokens $tokens): int
  86556. {
  86557. if ($tokens[$index]->equals('}')) {
  86558. return $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  86559. }
  86560. if ($tokens[$index]->equals(')')) {
  86561. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  86562. $startIndex = $tokens->getPrevMeaningfulToken($startIndex);
  86563. if (!$tokens[$startIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86564. return $startIndex;
  86565. }
  86566. }
  86567. if ($tokens[$index]->equals(',') && $this->commaIsPartOfImplementsList($index, $tokens)) {
  86568. --$index;
  86569. }
  86570. return $index;
  86571. }
  86572. private function commaIsPartOfImplementsList(int $index, Tokens $tokens): bool
  86573. {
  86574. do {
  86575. $index = $tokens->getPrevMeaningfulToken($index);
  86576. $current = $tokens[$index];
  86577. } while ($current->isGivenKind(T_STRING) || $current->equals(','));
  86578. return $current->isGivenKind(T_IMPLEMENTS);
  86579. }
  86580. }
  86581. <?php
  86582. declare(strict_types=1);
  86583. namespace PhpCsFixer\Fixer\ArrayNotation;
  86584. use PhpCsFixer\AbstractFixer;
  86585. use PhpCsFixer\FixerDefinition\CodeSample;
  86586. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86587. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86588. use PhpCsFixer\Tokenizer\Token;
  86589. use PhpCsFixer\Tokenizer\Tokens;
  86590. final class NoMultilineWhitespaceAroundDoubleArrowFixer extends AbstractFixer
  86591. {
  86592. public function getDefinition(): FixerDefinitionInterface
  86593. {
  86594. return new FixerDefinition(
  86595. 'Operator `=>` should not be surrounded by multi-line whitespaces.',
  86596. [new CodeSample("<?php\n\$a = array(1\n\n=> 2);\n")]
  86597. );
  86598. }
  86599. public function getPriority(): int
  86600. {
  86601. return 31;
  86602. }
  86603. public function isCandidate(Tokens $tokens): bool
  86604. {
  86605. return $tokens->isTokenKindFound(T_DOUBLE_ARROW);
  86606. }
  86607. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86608. {
  86609. foreach ($tokens as $index => $token) {
  86610. if (!$token->isGivenKind(T_DOUBLE_ARROW)) {
  86611. continue;
  86612. }
  86613. if (!$tokens[$index - 2]->isComment() || str_starts_with($tokens[$index - 2]->getContent(), '/*')) {
  86614. $this->fixWhitespace($tokens, $index - 1);
  86615. }
  86616. if (!$tokens[$index + 2]->isComment()) {
  86617. $this->fixWhitespace($tokens, $index + 1);
  86618. }
  86619. }
  86620. }
  86621. private function fixWhitespace(Tokens $tokens, int $index): void
  86622. {
  86623. $token = $tokens[$index];
  86624. if ($token->isWhitespace() && !$token->isWhitespace(" \t")) {
  86625. $tokens[$index] = new Token([T_WHITESPACE, rtrim($token->getContent()).' ']);
  86626. }
  86627. }
  86628. }
  86629. <?php
  86630. declare(strict_types=1);
  86631. namespace PhpCsFixer\Fixer\ArrayNotation;
  86632. use PhpCsFixer\AbstractFixer;
  86633. use PhpCsFixer\FixerDefinition\CodeSample;
  86634. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86635. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86636. use PhpCsFixer\Tokenizer\CT;
  86637. use PhpCsFixer\Tokenizer\Token;
  86638. use PhpCsFixer\Tokenizer\Tokens;
  86639. final class YieldFromArrayToYieldsFixer extends AbstractFixer
  86640. {
  86641. public function getDefinition(): FixerDefinitionInterface
  86642. {
  86643. return new FixerDefinition(
  86644. 'Yield from array must be unpacked to series of yields.',
  86645. [
  86646. new CodeSample('<?php function generate() {
  86647. yield from [
  86648. 1,
  86649. 2,
  86650. 3,
  86651. ];
  86652. }
  86653. '),
  86654. ],
  86655. 'The conversion will make the array in `yield from` changed in arrays of 1 less dimension.',
  86656. 'The rule is risky in case of `yield from` being used multiple times within single function scope, while using list-alike data sources (e.g. `function foo() { yield from ["a"]; yield from ["b"]; }`). It only matters when consuming such iterator with key-value context, because set of yielded keys may be changed after applying this rule.'
  86657. );
  86658. }
  86659. public function isRisky(): bool
  86660. {
  86661. return true;
  86662. }
  86663. public function isCandidate(Tokens $tokens): bool
  86664. {
  86665. return $tokens->isTokenKindFound(T_YIELD_FROM);
  86666. }
  86667. public function getPriority(): int
  86668. {
  86669. return 0;
  86670. }
  86671. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86672. {
  86673. $inserts = [];
  86674. foreach ($this->getYieldsFromToUnpack($tokens) as $index => [$startIndex, $endIndex]) {
  86675. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  86676. if ($tokens[$startIndex]->equals('(')) {
  86677. $prevStartIndex = $tokens->getPrevMeaningfulToken($startIndex);
  86678. $tokens->clearTokenAndMergeSurroundingWhitespace($prevStartIndex);
  86679. }
  86680. $tokens->clearTokenAndMergeSurroundingWhitespace($startIndex);
  86681. $tokens->clearTokenAndMergeSurroundingWhitespace($endIndex);
  86682. $arrayHasTrailingComma = false;
  86683. $startIndex = $tokens->getNextMeaningfulToken($startIndex);
  86684. $inserts[$startIndex] = [new Token([T_YIELD, 'yield']), new Token([T_WHITESPACE, ' '])];
  86685. foreach ($this->findArrayItemCommaIndex(
  86686. $tokens,
  86687. $startIndex,
  86688. $tokens->getPrevMeaningfulToken($endIndex),
  86689. ) as $commaIndex) {
  86690. $nextItemIndex = $tokens->getNextMeaningfulToken($commaIndex);
  86691. if ($nextItemIndex < $endIndex) {
  86692. $inserts[$nextItemIndex] = [new Token([T_YIELD, 'yield']), new Token([T_WHITESPACE, ' '])];
  86693. $tokens[$commaIndex] = new Token(';');
  86694. } else {
  86695. $arrayHasTrailingComma = true;
  86696. $tokens[$commaIndex] = new Token(';');
  86697. }
  86698. }
  86699. if (true === $arrayHasTrailingComma) {
  86700. $tokens->clearTokenAndMergeSurroundingWhitespace($tokens->getNextMeaningfulToken($endIndex));
  86701. }
  86702. }
  86703. $tokens->insertSlices($inserts);
  86704. }
  86705. private function getYieldsFromToUnpack(Tokens $tokens): iterable
  86706. {
  86707. $tokensCount = $tokens->count();
  86708. $index = 0;
  86709. while (++$index < $tokensCount) {
  86710. if (!$tokens[$index]->isGivenKind(T_YIELD_FROM)) {
  86711. continue;
  86712. }
  86713. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  86714. if (!$tokens[$prevIndex]->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
  86715. continue;
  86716. }
  86717. $arrayStartIndex = $tokens->getNextMeaningfulToken($index);
  86718. if (!$tokens[$arrayStartIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86719. continue;
  86720. }
  86721. if ($tokens[$arrayStartIndex]->isGivenKind(T_ARRAY)) {
  86722. $startIndex = $tokens->getNextTokenOfKind($arrayStartIndex, ['(']);
  86723. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  86724. } else {
  86725. $startIndex = $arrayStartIndex;
  86726. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  86727. }
  86728. if ($endIndex === $tokens->getNextMeaningfulToken($startIndex)) {
  86729. continue;
  86730. }
  86731. if ([] !== $tokens->findGivenKind(T_YIELD_FROM, $startIndex, $endIndex)) {
  86732. continue;
  86733. }
  86734. yield $index => [$startIndex, $endIndex];
  86735. }
  86736. }
  86737. private function findArrayItemCommaIndex(Tokens $tokens, int $startIndex, int $endIndex): iterable
  86738. {
  86739. for ($index = $startIndex; $index <= $endIndex; ++$index) {
  86740. $token = $tokens[$index];
  86741. $blockDefinitionProbe = Tokens::detectBlockType($token);
  86742. if (null !== $blockDefinitionProbe && true === $blockDefinitionProbe['isStart']) {
  86743. $index = $tokens->findBlockEnd($blockDefinitionProbe['type'], $index);
  86744. continue;
  86745. }
  86746. if (!$tokens[$index]->equals(',')) {
  86747. continue;
  86748. }
  86749. yield $index;
  86750. }
  86751. }
  86752. }
  86753. <?php
  86754. declare(strict_types=1);
  86755. namespace PhpCsFixer\Fixer\ArrayNotation;
  86756. use PhpCsFixer\AbstractProxyFixer;
  86757. use PhpCsFixer\Fixer\Basic\NoTrailingCommaInSinglelineFixer;
  86758. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  86759. use PhpCsFixer\FixerDefinition\CodeSample;
  86760. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86761. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86762. final class NoTrailingCommaInSinglelineArrayFixer extends AbstractProxyFixer implements DeprecatedFixerInterface
  86763. {
  86764. public function getDefinition(): FixerDefinitionInterface
  86765. {
  86766. return new FixerDefinition(
  86767. 'PHP single-line arrays should not have trailing comma.',
  86768. [new CodeSample("<?php\n\$a = array('sample', );\n")]
  86769. );
  86770. }
  86771. public function getSuccessorsNames(): array
  86772. {
  86773. return array_keys($this->proxyFixers);
  86774. }
  86775. protected function createProxyFixers(): array
  86776. {
  86777. $fixer = new NoTrailingCommaInSinglelineFixer();
  86778. $fixer->configure(['elements' => ['array']]);
  86779. return [$fixer];
  86780. }
  86781. }
  86782. <?php
  86783. declare(strict_types=1);
  86784. namespace PhpCsFixer\Fixer\ArrayNotation;
  86785. use PhpCsFixer\AbstractFixer;
  86786. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  86787. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  86788. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  86789. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  86790. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  86791. use PhpCsFixer\FixerDefinition\CodeSample;
  86792. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86793. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86794. use PhpCsFixer\Preg;
  86795. use PhpCsFixer\Tokenizer\CT;
  86796. use PhpCsFixer\Tokenizer\Token;
  86797. use PhpCsFixer\Tokenizer\Tokens;
  86798. /**
  86799. @phpstan-type
  86800. @phpstan-type
  86801. @implements
  86802. */
  86803. final class WhitespaceAfterCommaInArrayFixer extends AbstractFixer implements ConfigurableFixerInterface
  86804. {
  86805. /**
  86806. @use */
  86807. use ConfigurableFixerTrait;
  86808. public function getDefinition(): FixerDefinitionInterface
  86809. {
  86810. return new FixerDefinition(
  86811. 'In array declaration, there MUST be a whitespace after each comma.',
  86812. [
  86813. new CodeSample("<?php\n\$sample = array(1,'a',\$b,);\n"),
  86814. new CodeSample("<?php\n\$sample = [1,2, 3, 4, 5];\n", ['ensure_single_space' => true]),
  86815. ]
  86816. );
  86817. }
  86818. public function isCandidate(Tokens $tokens): bool
  86819. {
  86820. return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  86821. }
  86822. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  86823. {
  86824. return new FixerConfigurationResolver([
  86825. (new FixerOptionBuilder('ensure_single_space', 'If there are only horizontal whitespaces after the comma then ensure it is a single space.'))
  86826. ->setAllowedTypes(['bool'])
  86827. ->setDefault(false)
  86828. ->getOption(),
  86829. ]);
  86830. }
  86831. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86832. {
  86833. $tokensToInsert = [];
  86834. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  86835. if (!$tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86836. continue;
  86837. }
  86838. if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  86839. $startIndex = $index;
  86840. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
  86841. } else {
  86842. $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
  86843. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
  86844. }
  86845. for ($i = $endIndex - 1; $i > $startIndex; --$i) {
  86846. $i = $this->skipNonArrayElements($i, $tokens);
  86847. if (!$tokens[$i]->equals(',')) {
  86848. continue;
  86849. }
  86850. if (!$tokens[$i + 1]->isWhitespace()) {
  86851. $tokensToInsert[$i + 1] = new Token([T_WHITESPACE, ' ']);
  86852. } elseif (
  86853. true === $this->configuration['ensure_single_space']
  86854. && ' ' !== $tokens[$i + 1]->getContent()
  86855. && Preg::match('/^\h+$/', $tokens[$i + 1]->getContent())
  86856. && (!$tokens[$i + 2]->isComment() || Preg::match('/^\h+$/', $tokens[$i + 3]->getContent()))
  86857. ) {
  86858. $tokens[$i + 1] = new Token([T_WHITESPACE, ' ']);
  86859. }
  86860. }
  86861. }
  86862. if ([] !== $tokensToInsert) {
  86863. $tokens->insertSlices($tokensToInsert);
  86864. }
  86865. }
  86866. private function skipNonArrayElements(int $index, Tokens $tokens): int
  86867. {
  86868. if ($tokens[$index]->equals('}')) {
  86869. return $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  86870. }
  86871. if ($tokens[$index]->equals(')')) {
  86872. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  86873. $startIndex = $tokens->getPrevMeaningfulToken($startIndex);
  86874. if (!$tokens[$startIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  86875. return $startIndex;
  86876. }
  86877. }
  86878. if ($tokens[$index]->equals(',') && $this->commaIsPartOfImplementsList($index, $tokens)) {
  86879. --$index;
  86880. }
  86881. return $index;
  86882. }
  86883. private function commaIsPartOfImplementsList(int $index, Tokens $tokens): bool
  86884. {
  86885. do {
  86886. $index = $tokens->getPrevMeaningfulToken($index);
  86887. $current = $tokens[$index];
  86888. } while ($current->isGivenKind(T_STRING) || $current->equals(','));
  86889. return $current->isGivenKind(T_IMPLEMENTS);
  86890. }
  86891. }
  86892. <?php
  86893. declare(strict_types=1);
  86894. namespace PhpCsFixer\Fixer\ArrayNotation;
  86895. use PhpCsFixer\AbstractFixer;
  86896. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86897. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86898. use PhpCsFixer\FixerDefinition\VersionSpecification;
  86899. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  86900. use PhpCsFixer\Tokenizer\CT;
  86901. use PhpCsFixer\Tokenizer\Token;
  86902. use PhpCsFixer\Tokenizer\Tokens;
  86903. final class NormalizeIndexBraceFixer extends AbstractFixer
  86904. {
  86905. public function getDefinition(): FixerDefinitionInterface
  86906. {
  86907. return new FixerDefinition(
  86908. 'Array index should always be written by using square braces.',
  86909. [new VersionSpecificCodeSample(
  86910. "<?php\necho \$sample{\$index};\n",
  86911. new VersionSpecification(null, 8_04_00 - 1)
  86912. )]
  86913. );
  86914. }
  86915. public function isCandidate(Tokens $tokens): bool
  86916. {
  86917. return $tokens->isTokenKindFound(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN);
  86918. }
  86919. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86920. {
  86921. foreach ($tokens as $index => $token) {
  86922. if ($token->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
  86923. $tokens[$index] = new Token('[');
  86924. } elseif ($token->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE)) {
  86925. $tokens[$index] = new Token(']');
  86926. }
  86927. }
  86928. }
  86929. }
  86930. <?php
  86931. declare(strict_types=1);
  86932. namespace PhpCsFixer\Fixer\ListNotation;
  86933. use PhpCsFixer\AbstractFixer;
  86934. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  86935. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  86936. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  86937. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  86938. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  86939. use PhpCsFixer\FixerDefinition\CodeSample;
  86940. use PhpCsFixer\FixerDefinition\FixerDefinition;
  86941. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  86942. use PhpCsFixer\Tokenizer\CT;
  86943. use PhpCsFixer\Tokenizer\Token;
  86944. use PhpCsFixer\Tokenizer\Tokens;
  86945. /**
  86946. @phpstan-type
  86947. @phpstan-type
  86948. @implements
  86949. */
  86950. final class ListSyntaxFixer extends AbstractFixer implements ConfigurableFixerInterface
  86951. {
  86952. /**
  86953. @use */
  86954. use ConfigurableFixerTrait;
  86955. private ?int $candidateTokenKind = null;
  86956. public function getDefinition(): FixerDefinitionInterface
  86957. {
  86958. return new FixerDefinition(
  86959. 'List (`array` destructuring) assignment should be declared using the configured syntax.',
  86960. [
  86961. new CodeSample(
  86962. "<?php\nlist(\$sample) = \$array;\n"
  86963. ),
  86964. new CodeSample(
  86965. "<?php\n[\$sample] = \$array;\n",
  86966. ['syntax' => 'long']
  86967. ),
  86968. ]
  86969. );
  86970. }
  86971. public function getPriority(): int
  86972. {
  86973. return 2;
  86974. }
  86975. public function isCandidate(Tokens $tokens): bool
  86976. {
  86977. return $tokens->isTokenKindFound($this->candidateTokenKind);
  86978. }
  86979. protected function configurePostNormalisation(): void
  86980. {
  86981. $this->candidateTokenKind = 'long' === $this->configuration['syntax'] ? CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN : T_LIST;
  86982. }
  86983. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  86984. {
  86985. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  86986. if ($tokens[$index]->isGivenKind($this->candidateTokenKind)) {
  86987. if (T_LIST === $this->candidateTokenKind) {
  86988. $this->fixToShortSyntax($tokens, $index);
  86989. } else {
  86990. $this->fixToLongSyntax($tokens, $index);
  86991. }
  86992. }
  86993. }
  86994. }
  86995. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  86996. {
  86997. return new FixerConfigurationResolver([
  86998. (new FixerOptionBuilder('syntax', 'Whether to use the `long` or `short` syntax for array destructuring.'))
  86999. ->setAllowedValues(['long', 'short'])
  87000. ->setDefault('short')
  87001. ->getOption(),
  87002. ]);
  87003. }
  87004. private function fixToLongSyntax(Tokens $tokens, int $index): void
  87005. {
  87006. static $typesOfInterest = [
  87007. [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE],
  87008. '[',
  87009. ];
  87010. $closeIndex = $tokens->getNextTokenOfKind($index, $typesOfInterest);
  87011. if (!$tokens[$closeIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE)) {
  87012. return;
  87013. }
  87014. $tokens[$index] = new Token('(');
  87015. $tokens[$closeIndex] = new Token(')');
  87016. $tokens->insertAt($index, new Token([T_LIST, 'list']));
  87017. }
  87018. private function fixToShortSyntax(Tokens $tokens, int $index): void
  87019. {
  87020. $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
  87021. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
  87022. $tokens[$openIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  87023. $tokens[$closeIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  87024. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  87025. }
  87026. }
  87027. <?php
  87028. declare(strict_types=1);
  87029. namespace PhpCsFixer\Fixer\Operator;
  87030. use PhpCsFixer\AbstractFixer;
  87031. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  87032. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  87033. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  87034. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  87035. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  87036. use PhpCsFixer\FixerDefinition\FixerDefinition;
  87037. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  87038. use PhpCsFixer\FixerDefinition\VersionSpecification;
  87039. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  87040. use PhpCsFixer\Tokenizer\CT;
  87041. use PhpCsFixer\Tokenizer\Token;
  87042. use PhpCsFixer\Tokenizer\Tokens;
  87043. /**
  87044. @phpstan-type
  87045. @phpstan-type
  87046. @implements
  87047. */
  87048. final class NewExpressionParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
  87049. {
  87050. /**
  87051. @use */
  87052. use ConfigurableFixerTrait;
  87053. public function getDefinition(): FixerDefinitionInterface
  87054. {
  87055. return new FixerDefinition(
  87056. 'All `new` expressions with a further call must (not) be wrapped in parentheses.',
  87057. [
  87058. new VersionSpecificCodeSample(
  87059. "<?php\n\n(new Foo())->bar();\n",
  87060. new VersionSpecification(8_04_00)
  87061. ),
  87062. new VersionSpecificCodeSample(
  87063. "<?php\n\n(new class {})->bar();\n",
  87064. new VersionSpecification(8_04_00)
  87065. ),
  87066. new VersionSpecificCodeSample(
  87067. "<?php\n\nnew Foo()->bar();\n",
  87068. new VersionSpecification(8_04_00),
  87069. ['use_parentheses' => true]
  87070. ),
  87071. new VersionSpecificCodeSample(
  87072. "<?php\n\nnew class {}->bar();\n",
  87073. new VersionSpecification(8_04_00),
  87074. ['use_parentheses' => true]
  87075. ),
  87076. ]
  87077. );
  87078. }
  87079. public function getPriority(): int
  87080. {
  87081. return 29;
  87082. }
  87083. public function isCandidate(Tokens $tokens): bool
  87084. {
  87085. return \PHP_VERSION_ID >= 8_04_00 && $tokens->isTokenKindFound(T_NEW);
  87086. }
  87087. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  87088. {
  87089. return new FixerConfigurationResolver([
  87090. (new FixerOptionBuilder('use_parentheses', 'Whether `new` expressions with a further call should be wrapped in parentheses or not.'))
  87091. ->setAllowedTypes(['bool'])
  87092. ->setDefault(false)
  87093. ->getOption(),
  87094. ]);
  87095. }
  87096. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  87097. {
  87098. $useParentheses = $this->configuration['use_parentheses'];
  87099. for ($index = $tokens->count() - 3; $index > 0; --$index) {
  87100. if (!$tokens[$index]->isGivenKind(T_NEW)) {
  87101. continue;
  87102. }
  87103. $classStartIndex = $tokens->getNextMeaningfulToken($index);
  87104. if (null === $classStartIndex) {
  87105. return;
  87106. }
  87107. if ($tokens[$classStartIndex]->isGivenKind(T_CLASS)) {
  87108. $nextIndex = $tokens->getNextMeaningfulToken($classStartIndex);
  87109. if ($tokens[$nextIndex]->equals('(')) {
  87110. $nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  87111. } else {
  87112. $nextIndex = $classStartIndex;
  87113. }
  87114. $bodyStartIndex = $tokens->getNextTokenOfKind($nextIndex, ['{']);
  87115. $bodyEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $bodyStartIndex);
  87116. if ($useParentheses) {
  87117. $this->ensureWrappedInParentheses($tokens, $index, $bodyEndIndex);
  87118. } else {
  87119. $this->ensureNotWrappedInParentheses($tokens, $index, $bodyEndIndex);
  87120. }
  87121. continue;
  87122. }
  87123. $classEndIndex = $this->findClassEndIndex($tokens, $classStartIndex);
  87124. if (null === $classEndIndex) {
  87125. continue;
  87126. }
  87127. $nextIndex = $tokens->getNextMeaningfulToken($classEndIndex);
  87128. if (!$tokens[$nextIndex]->equals('(')) {
  87129. continue;
  87130. }
  87131. $argsEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
  87132. if ($useParentheses) {
  87133. $this->ensureWrappedInParentheses($tokens, $index, $argsEndIndex);
  87134. } else {
  87135. $this->ensureNotWrappedInParentheses($tokens, $index, $argsEndIndex);
  87136. }
  87137. }
  87138. }
  87139. private function ensureWrappedInParentheses(Tokens $tokens, int $exprStartIndex, int $exprEndIndex): void
  87140. {
  87141. $prevIndex = $tokens->getPrevMeaningfulToken($exprStartIndex);
  87142. $nextIndex = $tokens->getNextMeaningfulToken($exprEndIndex);
  87143. if ($tokens[$prevIndex]->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_OPEN)
  87144. && $tokens[$nextIndex]->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_CLOSE)
  87145. ) {
  87146. return;
  87147. }
  87148. if (!$tokens[$nextIndex]->isObjectOperator() && !$tokens[$nextIndex]->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  87149. return;
  87150. }
  87151. $tokens->insertAt($exprStartIndex, [new Token([CT::T_BRACE_CLASS_INSTANTIATION_OPEN, '('])]);
  87152. $tokens->insertAt($exprEndIndex + 2, [new Token([CT::T_BRACE_CLASS_INSTANTIATION_CLOSE, ')'])]);
  87153. }
  87154. private function ensureNotWrappedInParentheses(Tokens $tokens, int $exprStartIndex, int $exprEndIndex): void
  87155. {
  87156. $prevIndex = $tokens->getPrevMeaningfulToken($exprStartIndex);
  87157. $nextIndex = $tokens->getNextMeaningfulToken($exprEndIndex);
  87158. if (!$tokens[$prevIndex]->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_OPEN)
  87159. || !$tokens[$nextIndex]->isGivenKind(CT::T_BRACE_CLASS_INSTANTIATION_CLOSE)
  87160. ) {
  87161. return;
  87162. }
  87163. $operatorIndex = $tokens->getNextMeaningfulToken($nextIndex);
  87164. if (!$tokens[$operatorIndex]->isObjectOperator() && !$tokens[$operatorIndex]->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  87165. return;
  87166. }
  87167. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  87168. $tokens->clearTokenAndMergeSurroundingWhitespace($nextIndex);
  87169. }
  87170. private function findClassEndIndex(Tokens $tokens, int $index): ?int
  87171. {
  87172. if ($tokens[$index]->equals('(')) {
  87173. return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  87174. }
  87175. static $nextTokens = [
  87176. [T_STRING],
  87177. [T_NS_SEPARATOR],
  87178. [CT::T_NAMESPACE_OPERATOR],
  87179. [T_VARIABLE],
  87180. '$',
  87181. [CT::T_DYNAMIC_VAR_BRACE_OPEN],
  87182. '[',
  87183. [T_OBJECT_OPERATOR],
  87184. [T_NULLSAFE_OBJECT_OPERATOR],
  87185. [T_PAAMAYIM_NEKUDOTAYIM],
  87186. ];
  87187. if (!$tokens[$index]->equalsAny($nextTokens)) {
  87188. return null;
  87189. }
  87190. while ($tokens[$index]->equalsAny($nextTokens)) {
  87191. $blockType = Tokens::detectBlockType($tokens[$index]);
  87192. if (null !== $blockType) {
  87193. $index = $tokens->findBlockEnd($blockType['type'], $index);
  87194. }
  87195. $index = $tokens->getNextMeaningfulToken($index);
  87196. }
  87197. return $index - 1;
  87198. }
  87199. }
  87200. <?php
  87201. declare(strict_types=1);
  87202. namespace PhpCsFixer\Fixer\Operator;
  87203. use PhpCsFixer\AbstractFixer;
  87204. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  87205. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  87206. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  87207. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  87208. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  87209. use PhpCsFixer\FixerDefinition\CodeSample;
  87210. use PhpCsFixer\FixerDefinition\FixerDefinition;
  87211. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  87212. use PhpCsFixer\Tokenizer\Token;
  87213. use PhpCsFixer\Tokenizer\Tokens;
  87214. /**
  87215. @phpstan-type
  87216. @phpstan-type
  87217. @implements
  87218. */
  87219. final class ConcatSpaceFixer extends AbstractFixer implements ConfigurableFixerInterface
  87220. {
  87221. /**
  87222. @use */
  87223. use ConfigurableFixerTrait;
  87224. public function getDefinition(): FixerDefinitionInterface
  87225. {
  87226. return new FixerDefinition(
  87227. 'Concatenation should be spaced according to configuration.',
  87228. [
  87229. new CodeSample(
  87230. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n"
  87231. ),
  87232. new CodeSample(
  87233. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n",
  87234. ['spacing' => 'none']
  87235. ),
  87236. new CodeSample(
  87237. "<?php\n\$foo = 'bar' . 3 . 'baz'.'qux';\n",
  87238. ['spacing' => 'one']
  87239. ),
  87240. ]
  87241. );
  87242. }
  87243. public function getPriority(): int
  87244. {
  87245. return 0;
  87246. }
  87247. public function isCandidate(Tokens $tokens): bool
  87248. {
  87249. return $tokens->isTokenKindFound('.');
  87250. }
  87251. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  87252. {
  87253. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  87254. if ($tokens[$index]->equals('.')) {
  87255. if ('one' === $this->configuration['spacing']) {
  87256. $this->fixConcatenationToSingleSpace($tokens, $index);
  87257. } else {
  87258. $this->fixConcatenationToNoSpace($tokens, $index);
  87259. }
  87260. }
  87261. }
  87262. }
  87263. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  87264. {
  87265. return new FixerConfigurationResolver([
  87266. (new FixerOptionBuilder('spacing', 'Spacing to apply around concatenation operator.'))
  87267. ->setAllowedValues(['one', 'none'])
  87268. ->setDefault('none')
  87269. ->getOption(),
  87270. ]);
  87271. }
  87272. private function fixConcatenationToNoSpace(Tokens $tokens, int $index): void
  87273. {
  87274. $prevNonWhitespaceToken = $tokens[$tokens->getPrevNonWhitespace($index)];
  87275. if (!$prevNonWhitespaceToken->isGivenKind([T_LNUMBER, T_COMMENT, T_DOC_COMMENT]) || str_starts_with($prevNonWhitespaceToken->getContent(), '/*')) {
  87276. $tokens->removeLeadingWhitespace($index, " \t");
  87277. }
  87278. if (!$tokens[$tokens->getNextNonWhitespace($index)]->isGivenKind([T_LNUMBER, T_COMMENT, T_DOC_COMMENT])) {
  87279. $tokens->removeTrailingWhitespace($index, " \t");
  87280. }
  87281. }
  87282. private function fixConcatenationToSingleSpace(Tokens $tokens, int $index): void
  87283. {
  87284. $this->fixWhiteSpaceAroundConcatToken($tokens, $index, 1);
  87285. $this->fixWhiteSpaceAroundConcatToken($tokens, $index, -1);
  87286. }
  87287. private function fixWhiteSpaceAroundConcatToken(Tokens $tokens, int $index, int $offset): void
  87288. {
  87289. if (-1 !== $offset && 1 !== $offset) {
  87290. throw new \InvalidArgumentException(\sprintf(
  87291. 'Expected `-1|1` for "$offset", got "%s"',
  87292. $offset
  87293. ));
  87294. }
  87295. $offsetIndex = $index + $offset;
  87296. if (!$tokens[$offsetIndex]->isWhitespace()) {
  87297. $tokens->insertAt($index + (1 === $offset ? 1 : 0), new Token([T_WHITESPACE, ' ']));
  87298. return;
  87299. }
  87300. if (str_contains($tokens[$offsetIndex]->getContent(), "\n")) {
  87301. return;
  87302. }
  87303. if ($tokens[$index + $offset * 2]->isComment()) {
  87304. return;
  87305. }
  87306. $tokens[$offsetIndex] = new Token([T_WHITESPACE, ' ']);
  87307. }
  87308. }
  87309. <?php
  87310. declare(strict_types=1);
  87311. namespace PhpCsFixer\Fixer\Operator;
  87312. use PhpCsFixer\Fixer\AbstractShortOperatorFixer;
  87313. use PhpCsFixer\FixerDefinition\CodeSample;
  87314. use PhpCsFixer\FixerDefinition\FixerDefinition;
  87315. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  87316. use PhpCsFixer\Tokenizer\FCT;
  87317. use PhpCsFixer\Tokenizer\Token;
  87318. use PhpCsFixer\Tokenizer\Tokens;
  87319. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  87320. final class LongToShorthandOperatorFixer extends AbstractShortOperatorFixer
  87321. {
  87322. private const OPERATORS = [
  87323. '+' => [T_PLUS_EQUAL, '+='],
  87324. '-' => [T_MINUS_EQUAL, '-='],
  87325. '*' => [T_MUL_EQUAL, '*='],
  87326. '/' => [T_DIV_EQUAL, '/='],
  87327. '&' => [T_AND_EQUAL, '&='],
  87328. '.' => [T_CONCAT_EQUAL, '.='],
  87329. '%' => [T_MOD_EQUAL, '%='],
  87330. '|' => [T_OR_EQUAL, '|='],
  87331. '^' => [T_XOR_EQUAL, '^='],
  87332. ];
  87333. private array $operatorTypes;
  87334. private TokensAnalyzer $tokensAnalyzer;
  87335. public function getDefinition(): FixerDefinitionInterface
  87336. {
  87337. return new FixerDefinition(
  87338. 'Shorthand notation for operators should be used if possible.',
  87339. [
  87340. new CodeSample("<?php\n\$i = \$i + 10;\n"),
  87341. ],
  87342. null,
  87343. 'Risky when applying for string offsets (e.g. `<?php $text = "foo"; $text[0] = $text[0] & "\x7F";`).',
  87344. );
  87345. }
  87346. public function getPriority(): int
  87347. {
  87348. return 17;
  87349. }
  87350. public function isRisky(): bool
  87351. {
  87352. return true;
  87353. }
  87354. public function isCandidate(Tokens $tokens): bool
  87355. {
  87356. return $tokens->isAnyTokenKindsFound([...array_keys(self::OPERATORS), FCT::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, FCT::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG]);
  87357. }
  87358. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  87359. {
  87360. $this->operatorTypes = array_keys(self::OPERATORS);
  87361. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  87362. parent::applyFix($file, $tokens);
  87363. }
  87364. protected function isOperatorTokenCandidate(Tokens $tokens, int $index): bool
  87365. {
  87366. if (!$tokens[$index]->equalsAny($this->operatorTypes)) {
  87367. return false;
  87368. }
  87369. while (null !== $index) {
  87370. $index = $tokens->getNextMeaningfulToken($index);
  87371. $otherToken = $tokens[$index];
  87372. if ($otherToken->equalsAny([';', [T_CLOSE_TAG]])) {
  87373. return true;
  87374. }
  87375. if ($otherToken->equals('?') || $otherToken->isGivenKind(T_INSTANCEOF)) {
  87376. return false;
  87377. }
  87378. $blockType = Tokens::detectBlockType($otherToken);
  87379. if (null !== $blockType) {
  87380. if (false === $blockType['isStart']) {
  87381. return true;
  87382. }
  87383. $index = $tokens->findBlockEnd($blockType['type'], $index);
  87384. continue;
  87385. }
  87386. if ($this->tokensAnalyzer->isBinaryOperator($index)) {
  87387. return false;
  87388. }
  87389. }
  87390. return false;
  87391. }
  87392. protected function getReplacementToken(Token $token): Token
  87393. {
  87394. \assert(isset(self::OPERATORS[$token->getContent()]));
  87395. return new Token(self::OPERATORS[$token->getContent()]);
  87396. }
  87397. }
  87398. <?php
  87399. declare(strict_types=1);
  87400. namespace PhpCsFixer\Fixer\Operator;
  87401. use PhpCsFixer\AbstractFixer;
  87402. use PhpCsFixer\FixerDefinition\CodeSample;
  87403. use PhpCsFixer\FixerDefinition\FixerDefinition;
  87404. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  87405. use PhpCsFixer\Tokenizer\Tokens;
  87406. final class NotOperatorWithSuccessorSpaceFixer extends AbstractFixer
  87407. {
  87408. public function getDefinition(): FixerDefinitionInterface
  87409. {
  87410. return new FixerDefinition(
  87411. 'Logical NOT operators (`!`) should have one trailing whitespace.',
  87412. [new CodeSample(
  87413. '<?php
  87414. if (!$bar) {
  87415. echo "Help!";
  87416. }
  87417. '
  87418. )]
  87419. );
  87420. }
  87421. public function getPriority(): int
  87422. {
  87423. return -10;
  87424. }
  87425. public function isCandidate(Tokens $tokens): bool
  87426. {
  87427. return $tokens->isTokenKindFound('!');
  87428. }
  87429. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  87430. {
  87431. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  87432. $token = $tokens[$index];
  87433. if ($token->equals('!')) {
  87434. $tokens->ensureWhitespaceAtIndex($index + 1, 0, ' ');
  87435. }
  87436. }
  87437. }
  87438. }
  87439. <?php
  87440. declare(strict_types=1);
  87441. namespace PhpCsFixer\Fixer\Operator;
  87442. use PhpCsFixer\AbstractFixer;
  87443. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  87444. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  87445. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  87446. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  87447. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  87448. use PhpCsFixer\FixerDefinition\CodeSample;
  87449. use PhpCsFixer\FixerDefinition\FixerDefinition;
  87450. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  87451. use PhpCsFixer\Preg;
  87452. use PhpCsFixer\Tokenizer\CT;
  87453. use PhpCsFixer\Tokenizer\Token;
  87454. use PhpCsFixer\Tokenizer\Tokens;
  87455. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  87456. use PhpCsFixer\Utils;
  87457. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  87458. /**
  87459. @phpstan-type
  87460. @phpstan-type
  87461. @implements
  87462. */
  87463. final class BinaryOperatorSpacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  87464. {
  87465. /**
  87466. @use */
  87467. use ConfigurableFixerTrait;
  87468. public const SINGLE_SPACE = 'single_space';
  87469. public const AT_LEAST_SINGLE_SPACE = 'at_least_single_space';
  87470. public const NO_SPACE = 'no_space';
  87471. public const ALIGN = 'align';
  87472. public const ALIGN_BY_SCOPE = 'align_by_scope';
  87473. public const ALIGN_SINGLE_SPACE = 'align_single_space';
  87474. public const ALIGN_SINGLE_SPACE_BY_SCOPE = 'align_single_space_by_scope';
  87475. public const ALIGN_SINGLE_SPACE_MINIMAL = 'align_single_space_minimal';
  87476. public const ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE = 'align_single_space_minimal_by_scope';
  87477. /**
  87478. @const
  87479. */
  87480. public const ALIGN_PLACEHOLDER = "\x2 ALIGNABLE%d \x3";
  87481. private const SUPPORTED_OPERATORS = [
  87482. '=',
  87483. '*',
  87484. '/',
  87485. '%',
  87486. '<',
  87487. '>',
  87488. '|',
  87489. '^',
  87490. '+',
  87491. '-',
  87492. '&',
  87493. '&=',
  87494. '&&',
  87495. '||',
  87496. '.=',
  87497. '/=',
  87498. '=>',
  87499. '==',
  87500. '>=',
  87501. '===',
  87502. '!=',
  87503. '<>',
  87504. '!==',
  87505. '<=',
  87506. 'and',
  87507. 'or',
  87508. 'xor',
  87509. '-=',
  87510. '%=',
  87511. '*=',
  87512. '|=',
  87513. '+=',
  87514. '<<',
  87515. '<<=',
  87516. '>>',
  87517. '>>=',
  87518. '^=',
  87519. '**',
  87520. '**=',
  87521. '<=>',
  87522. '??',
  87523. '??=',
  87524. ];
  87525. private const ALLOWED_VALUES = [
  87526. self::ALIGN,
  87527. self::ALIGN_BY_SCOPE,
  87528. self::ALIGN_SINGLE_SPACE,
  87529. self::ALIGN_SINGLE_SPACE_MINIMAL,
  87530. self::ALIGN_SINGLE_SPACE_BY_SCOPE,
  87531. self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE,
  87532. self::SINGLE_SPACE,
  87533. self::NO_SPACE,
  87534. self::AT_LEAST_SINGLE_SPACE,
  87535. null,
  87536. ];
  87537. private int $deepestLevel;
  87538. private int $currentLevel;
  87539. private TokensAnalyzer $tokensAnalyzer;
  87540. private array $alignOperatorTokens = [];
  87541. private array $operators = [];
  87542. public function getDefinition(): FixerDefinitionInterface
  87543. {
  87544. return new FixerDefinition(
  87545. 'Binary operators should be surrounded by space as configured.',
  87546. [
  87547. new CodeSample(
  87548. "<?php\n\$a= 1 + \$b^ \$d !== \$e or \$f;\n"
  87549. ),
  87550. new CodeSample(
  87551. '<?php
  87552. $aa= 1;
  87553. $b=2;
  87554. $c = $d xor $e;
  87555. $f -= 1;
  87556. ',
  87557. ['operators' => ['=' => self::ALIGN, 'xor' => null]]
  87558. ),
  87559. new CodeSample(
  87560. '<?php
  87561. $a = $b +=$c;
  87562. $d = $ee+=$f;
  87563. $g = $b +=$c;
  87564. $h = $ee+=$f;
  87565. ',
  87566. ['operators' => ['+=' => self::ALIGN_SINGLE_SPACE]]
  87567. ),
  87568. new CodeSample(
  87569. '<?php
  87570. $a = $b===$c;
  87571. $d = $f === $g;
  87572. $h = $i=== $j;
  87573. ',
  87574. ['operators' => ['===' => self::ALIGN_SINGLE_SPACE_MINIMAL]]
  87575. ),
  87576. new CodeSample(
  87577. '<?php
  87578. $foo = \json_encode($bar, JSON_PRESERVE_ZERO_FRACTION | JSON_PRETTY_PRINT);
  87579. ',
  87580. ['operators' => ['|' => self::NO_SPACE]]
  87581. ),
  87582. new CodeSample(
  87583. '<?php
  87584. $array = [
  87585. "foo" => 1,
  87586. "baaaaaaaaaaar" => 11,
  87587. ];
  87588. ',
  87589. ['operators' => ['=>' => self::SINGLE_SPACE]]
  87590. ),
  87591. new CodeSample(
  87592. '<?php
  87593. $array = [
  87594. "foo" => 12,
  87595. "baaaaaaaaaaar" => 13,
  87596. "baz" => 1,
  87597. ];
  87598. ',
  87599. ['operators' => ['=>' => self::ALIGN]]
  87600. ),
  87601. new CodeSample(
  87602. '<?php
  87603. $array = [
  87604. "foo" => 12,
  87605. "baaaaaaaaaaar" => 13,
  87606. "baz" => 1,
  87607. ];
  87608. ',
  87609. ['operators' => ['=>' => self::ALIGN_BY_SCOPE]]
  87610. ),
  87611. new CodeSample(
  87612. '<?php
  87613. $array = [
  87614. "foo" => 12,
  87615. "baaaaaaaaaaar" => 13,
  87616. "baz" => 1,
  87617. ];
  87618. ',
  87619. ['operators' => ['=>' => self::ALIGN_SINGLE_SPACE]]
  87620. ),
  87621. new CodeSample(
  87622. '<?php
  87623. $array = [
  87624. "foo" => 12,
  87625. "baaaaaaaaaaar" => 13,
  87626. "baz" => 1,
  87627. ];
  87628. ',
  87629. ['operators' => ['=>' => self::ALIGN_SINGLE_SPACE_BY_SCOPE]]
  87630. ),
  87631. new CodeSample(
  87632. '<?php
  87633. $array = [
  87634. "foo" => 12,
  87635. "baaaaaaaaaaar" => 13,
  87636. "baz" => 1,
  87637. ];
  87638. ',
  87639. ['operators' => ['=>' => self::ALIGN_SINGLE_SPACE_MINIMAL]]
  87640. ),
  87641. new CodeSample(
  87642. '<?php
  87643. $array = [
  87644. "foo" => 12,
  87645. "baaaaaaaaaaar" => 13,
  87646. "baz" => 1,
  87647. ];
  87648. ',
  87649. ['operators' => ['=>' => self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE]]
  87650. ),
  87651. ]
  87652. );
  87653. }
  87654. public function getPriority(): int
  87655. {
  87656. return -32;
  87657. }
  87658. public function isCandidate(Tokens $tokens): bool
  87659. {
  87660. return true;
  87661. }
  87662. protected function configurePostNormalisation(): void
  87663. {
  87664. $this->operators = $this->resolveOperatorsFromConfig();
  87665. }
  87666. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  87667. {
  87668. $this->tokensAnalyzer = new TokensAnalyzer($tokens);
  87669. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  87670. if (!$this->tokensAnalyzer->isBinaryOperator($index)) {
  87671. continue;
  87672. }
  87673. if ('=' === $tokens[$index]->getContent()) {
  87674. $isDeclare = $this->isEqualPartOfDeclareStatement($tokens, $index);
  87675. if (false === $isDeclare) {
  87676. $this->fixWhiteSpaceAroundOperator($tokens, $index);
  87677. } else {
  87678. $index = $isDeclare;
  87679. }
  87680. } else {
  87681. $this->fixWhiteSpaceAroundOperator($tokens, $index);
  87682. }
  87683. --$index;
  87684. }
  87685. if (\count($this->alignOperatorTokens) > 0) {
  87686. $this->fixAlignment($tokens, $this->alignOperatorTokens);
  87687. }
  87688. }
  87689. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  87690. {
  87691. return new FixerConfigurationResolver([
  87692. (new FixerOptionBuilder('default', 'Default fix strategy.'))
  87693. ->setDefault(self::SINGLE_SPACE)
  87694. ->setAllowedValues(self::ALLOWED_VALUES)
  87695. ->getOption(),
  87696. (new FixerOptionBuilder('operators', 'Dictionary of `binary operator` => `fix strategy` values that differ from the default strategy. Supported are: '.Utils::naturalLanguageJoinWithBackticks(self::SUPPORTED_OPERATORS).'.'))
  87697. ->setAllowedTypes(['array<string, ?string>'])
  87698. ->setAllowedValues([static function (array $option): bool {
  87699. foreach ($option as $operator => $value) {
  87700. if (!\in_array($operator, self::SUPPORTED_OPERATORS, true)) {
  87701. throw new InvalidOptionsException(
  87702. \sprintf(
  87703. 'Unexpected "operators" key, expected any of %s, got "%s".',
  87704. Utils::naturalLanguageJoin(self::SUPPORTED_OPERATORS),
  87705. \gettype($operator).'#'.$operator
  87706. )
  87707. );
  87708. }
  87709. if (!\in_array($value, self::ALLOWED_VALUES, true)) {
  87710. throw new InvalidOptionsException(
  87711. \sprintf(
  87712. 'Unexpected value for operator "%s", expected any of %s, got "%s".',
  87713. $operator,
  87714. Utils::naturalLanguageJoin(array_map(
  87715. static fn ($value): string => Utils::toString($value),
  87716. self::ALLOWED_VALUES
  87717. )),
  87718. \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value)
  87719. )
  87720. );
  87721. }
  87722. }
  87723. return true;
  87724. }])
  87725. ->setDefault([])
  87726. ->getOption(),
  87727. ]);
  87728. }
  87729. private function fixWhiteSpaceAroundOperator(Tokens $tokens, int $index): void
  87730. {
  87731. $tokenContent = strtolower($tokens[$index]->getContent());
  87732. if (!\array_key_exists($tokenContent, $this->operators)) {
  87733. return;
  87734. }
  87735. if (self::SINGLE_SPACE === $this->operators[$tokenContent]) {
  87736. $this->fixWhiteSpaceAroundOperatorToSingleSpace($tokens, $index);
  87737. return;
  87738. }
  87739. if (self::AT_LEAST_SINGLE_SPACE === $this->operators[$tokenContent]) {
  87740. $this->fixWhiteSpaceAroundOperatorToAtLeastSingleSpace($tokens, $index);
  87741. return;
  87742. }
  87743. if (self::NO_SPACE === $this->operators[$tokenContent]) {
  87744. $this->fixWhiteSpaceAroundOperatorToNoSpace($tokens, $index);
  87745. return;
  87746. }
  87747. $this->alignOperatorTokens[$tokenContent] = $this->operators[$tokenContent];
  87748. if (
  87749. self::ALIGN === $this->operators[$tokenContent]
  87750. || self::ALIGN_BY_SCOPE === $this->operators[$tokenContent]
  87751. ) {
  87752. return;
  87753. }
  87754. if ($tokens[$index + 1]->isWhitespace()) {
  87755. if (
  87756. self::ALIGN_SINGLE_SPACE_MINIMAL === $this->operators[$tokenContent]
  87757. || self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE === $this->operators[$tokenContent]
  87758. ) {
  87759. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  87760. }
  87761. return;
  87762. }
  87763. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  87764. }
  87765. private function fixWhiteSpaceAroundOperatorToSingleSpace(Tokens $tokens, int $index): void
  87766. {
  87767. if ($tokens[$index + 1]->isWhitespace()) {
  87768. $content = $tokens[$index + 1]->getContent();
  87769. if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($index + 1)]->isComment()) {
  87770. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  87771. }
  87772. } else {
  87773. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  87774. }
  87775. if ($tokens[$index - 1]->isWhitespace()) {
  87776. $content = $tokens[$index - 1]->getContent();
  87777. if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  87778. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  87779. }
  87780. } else {
  87781. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  87782. }
  87783. }
  87784. private function fixWhiteSpaceAroundOperatorToAtLeastSingleSpace(Tokens $tokens, int $index): void
  87785. {
  87786. if (!$tokens[$index + 1]->isWhitespace()) {
  87787. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  87788. }
  87789. if (!$tokens[$index - 1]->isWhitespace()) {
  87790. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  87791. }
  87792. }
  87793. private function fixWhiteSpaceAroundOperatorToNoSpace(Tokens $tokens, int $index): void
  87794. {
  87795. if ($tokens[$index + 1]->isWhitespace()) {
  87796. $content = $tokens[$index + 1]->getContent();
  87797. if (!str_contains($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($index + 1)]->isComment()) {
  87798. $tokens->clearAt($index + 1);
  87799. }
  87800. }
  87801. if ($tokens[$index - 1]->isWhitespace()) {
  87802. $content = $tokens[$index - 1]->getContent();
  87803. if (!str_contains($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()) {
  87804. $tokens->clearAt($index - 1);
  87805. }
  87806. }
  87807. }
  87808. private function isEqualPartOfDeclareStatement(Tokens $tokens, int $index)
  87809. {
  87810. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
  87811. if ($tokens[$prevMeaningfulIndex]->isGivenKind(T_STRING)) {
  87812. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulIndex);
  87813. if ($tokens[$prevMeaningfulIndex]->equals('(')) {
  87814. $prevMeaningfulIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulIndex);
  87815. if ($tokens[$prevMeaningfulIndex]->isGivenKind(T_DECLARE)) {
  87816. return $prevMeaningfulIndex;
  87817. }
  87818. }
  87819. }
  87820. return false;
  87821. }
  87822. private function resolveOperatorsFromConfig(): array
  87823. {
  87824. $operators = [];
  87825. if (null !== $this->configuration['default']) {
  87826. foreach (self::SUPPORTED_OPERATORS as $operator) {
  87827. $operators[$operator] = $this->configuration['default'];
  87828. }
  87829. }
  87830. foreach ($this->configuration['operators'] as $operator => $value) {
  87831. if (null === $value) {
  87832. unset($operators[$operator]);
  87833. } else {
  87834. $operators[$operator] = $value;
  87835. }
  87836. }
  87837. return $operators;
  87838. }
  87839. private function fixAlignment(Tokens $tokens, array $toAlign): void
  87840. {
  87841. $this->deepestLevel = 0;
  87842. $this->currentLevel = 0;
  87843. foreach ($toAlign as $tokenContent => $alignStrategy) {
  87844. $tokensClone = clone $tokens;
  87845. if ('=>' === $tokenContent) {
  87846. $this->injectAlignmentPlaceholdersForArrow($tokensClone, 0, \count($tokens));
  87847. } else {
  87848. $this->injectAlignmentPlaceholdersDefault($tokensClone, 0, \count($tokens), $tokenContent);
  87849. }
  87850. if (
  87851. self::ALIGN_SINGLE_SPACE === $alignStrategy
  87852. || self::ALIGN_SINGLE_SPACE_MINIMAL === $alignStrategy
  87853. || self::ALIGN_SINGLE_SPACE_BY_SCOPE === $alignStrategy
  87854. || self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE === $alignStrategy
  87855. ) {
  87856. if ('=>' === $tokenContent) {
  87857. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  87858. if ($tokens[$index]->isGivenKind(T_DOUBLE_ARROW)) {
  87859. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  87860. }
  87861. }
  87862. } elseif ('=' === $tokenContent) {
  87863. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  87864. if ('=' === $tokens[$index]->getContent() && !$this->isEqualPartOfDeclareStatement($tokens, $index) && $this->tokensAnalyzer->isBinaryOperator($index)) {
  87865. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  87866. }
  87867. }
  87868. } else {
  87869. for ($index = $tokens->count() - 2; $index > 0; --$index) {
  87870. $content = $tokens[$index]->getContent();
  87871. if (strtolower($content) === $tokenContent && $this->tokensAnalyzer->isBinaryOperator($index)) {
  87872. $this->fixWhiteSpaceBeforeOperator($tokensClone, $index, $alignStrategy);
  87873. }
  87874. }
  87875. }
  87876. }
  87877. $tokens->setCode($this->replacePlaceholders($tokensClone, $alignStrategy, $tokenContent));
  87878. }
  87879. }
  87880. private function injectAlignmentPlaceholdersDefault(Tokens $tokens, int $startAt, int $endAt, string $tokenContent): void
  87881. {
  87882. $newLineFoundSinceLastPlaceholder = true;
  87883. for ($index = $startAt; $index < $endAt; ++$index) {
  87884. $token = $tokens[$index];
  87885. $content = $token->getContent();
  87886. if (str_contains($content, "\n")) {
  87887. $newLineFoundSinceLastPlaceholder = true;
  87888. }
  87889. if (
  87890. strtolower($content) === $tokenContent
  87891. && $this->tokensAnalyzer->isBinaryOperator($index)
  87892. && ('=' !== $content || !$this->isEqualPartOfDeclareStatement($tokens, $index))
  87893. && $newLineFoundSinceLastPlaceholder
  87894. ) {
  87895. $tokens[$index] = new Token(\sprintf(self::ALIGN_PLACEHOLDER, $this->currentLevel).$content);
  87896. $newLineFoundSinceLastPlaceholder = false;
  87897. continue;
  87898. }
  87899. if ($token->isGivenKind(T_FN)) {
  87900. $from = $tokens->getNextMeaningfulToken($index);
  87901. $until = $this->tokensAnalyzer->getLastTokenIndexOfArrowFunction($index);
  87902. $this->injectAlignmentPlaceholders($tokens, $from + 1, $until - 1, $tokenContent);
  87903. $index = $until;
  87904. continue;
  87905. }
  87906. if ($token->isGivenKind([T_FUNCTION, T_CLASS])) {
  87907. $index = $tokens->getNextTokenOfKind($index, ['{', ';', '(']);
  87908. if ($tokens[$index]->equals('(')) {
  87909. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  87910. continue;
  87911. }
  87912. if ($tokens[$index]->equals(';')) {
  87913. continue;
  87914. }
  87915. $token = $tokens[$index];
  87916. }
  87917. if ($token->equals('{')) {
  87918. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  87919. $this->injectAlignmentPlaceholders($tokens, $index + 1, $until - 1, $tokenContent);
  87920. $index = $until;
  87921. continue;
  87922. }
  87923. if ($token->equals('(')) {
  87924. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  87925. $this->injectAlignmentPlaceholders($tokens, $index + 1, $until - 1, $tokenContent);
  87926. $index = $until;
  87927. continue;
  87928. }
  87929. if ($token->equals('[')) {
  87930. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  87931. continue;
  87932. }
  87933. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  87934. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);
  87935. $this->injectAlignmentPlaceholders($tokens, $index + 1, $until - 1, $tokenContent);
  87936. $index = $until;
  87937. continue;
  87938. }
  87939. }
  87940. }
  87941. private function injectAlignmentPlaceholders(Tokens $tokens, int $from, int $until, string $tokenContent): void
  87942. {
  87943. if ($tokens->isPartialCodeMultiline($from, $until)) {
  87944. ++$this->deepestLevel;
  87945. $currentLevel = $this->currentLevel;
  87946. $this->currentLevel = $this->deepestLevel;
  87947. $this->injectAlignmentPlaceholdersDefault($tokens, $from, $until, $tokenContent);
  87948. $this->currentLevel = $currentLevel;
  87949. }
  87950. }
  87951. private function injectAlignmentPlaceholdersForArrow(Tokens $tokens, int $startAt, int $endAt): void
  87952. {
  87953. $newLineFoundSinceLastPlaceholder = true;
  87954. $yieldFoundSinceLastPlaceholder = false;
  87955. for ($index = $startAt; $index < $endAt; ++$index) {
  87956. $token = $tokens[$index];
  87957. $content = $token->getContent();
  87958. if (str_contains($content, "\n")) {
  87959. $newLineFoundSinceLastPlaceholder = true;
  87960. }
  87961. if ($token->isGivenKind(T_YIELD)) {
  87962. $yieldFoundSinceLastPlaceholder = true;
  87963. }
  87964. if ($token->isGivenKind(T_FN)) {
  87965. $yieldFoundSinceLastPlaceholder = false;
  87966. $from = $tokens->getNextMeaningfulToken($index);
  87967. $until = $this->tokensAnalyzer->getLastTokenIndexOfArrowFunction($index);
  87968. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  87969. $index = $until;
  87970. continue;
  87971. }
  87972. if ($token->isGivenKind(T_ARRAY)) {
  87973. $yieldFoundSinceLastPlaceholder = false;
  87974. $from = $tokens->getNextMeaningfulToken($index);
  87975. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $from);
  87976. $index = $until;
  87977. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  87978. continue;
  87979. }
  87980. if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
  87981. $yieldFoundSinceLastPlaceholder = false;
  87982. $from = $index;
  87983. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $from);
  87984. $index = $until;
  87985. $this->injectArrayAlignmentPlaceholders($tokens, $from + 1, $until - 1);
  87986. continue;
  87987. }
  87988. if ($token->isGivenKind(T_DOUBLE_ARROW) && $newLineFoundSinceLastPlaceholder) {
  87989. if ($yieldFoundSinceLastPlaceholder) {
  87990. ++$this->deepestLevel;
  87991. ++$this->currentLevel;
  87992. }
  87993. $tokenContent = \sprintf(self::ALIGN_PLACEHOLDER, $this->currentLevel).$token->getContent();
  87994. $nextToken = $tokens[$index + 1];
  87995. if (!$nextToken->isWhitespace()) {
  87996. $tokenContent .= ' ';
  87997. } elseif ($nextToken->isWhitespace(" \t")) {
  87998. $tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
  87999. }
  88000. $tokens[$index] = new Token([T_DOUBLE_ARROW, $tokenContent]);
  88001. $newLineFoundSinceLastPlaceholder = false;
  88002. $yieldFoundSinceLastPlaceholder = false;
  88003. continue;
  88004. }
  88005. if ($token->equals(';')) {
  88006. ++$this->deepestLevel;
  88007. ++$this->currentLevel;
  88008. continue;
  88009. }
  88010. if ($token->equals(',')) {
  88011. for ($i = $index; $i < $endAt - 1; ++$i) {
  88012. if (str_contains($tokens[$i - 1]->getContent(), "\n")) {
  88013. $newLineFoundSinceLastPlaceholder = true;
  88014. break;
  88015. }
  88016. if ($tokens[$i + 1]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
  88017. $arrayStartIndex = $tokens[$i + 1]->isGivenKind(T_ARRAY)
  88018. ? $tokens->getNextMeaningfulToken($i + 1)
  88019. : $i + 1;
  88020. $blockType = Tokens::detectBlockType($tokens[$arrayStartIndex]);
  88021. $arrayEndIndex = $tokens->findBlockEnd($blockType['type'], $arrayStartIndex);
  88022. if ($tokens->isPartialCodeMultiline($arrayStartIndex, $arrayEndIndex)) {
  88023. break;
  88024. }
  88025. }
  88026. ++$index;
  88027. }
  88028. }
  88029. if ($token->equals('{')) {
  88030. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  88031. $this->injectArrayAlignmentPlaceholders($tokens, $index + 1, $until - 1);
  88032. $index = $until;
  88033. continue;
  88034. }
  88035. if ($token->equals('(')) {
  88036. $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  88037. $this->injectArrayAlignmentPlaceholders($tokens, $index + 1, $until - 1);
  88038. $index = $until;
  88039. continue;
  88040. }
  88041. }
  88042. }
  88043. private function injectArrayAlignmentPlaceholders(Tokens $tokens, int $from, int $until): void
  88044. {
  88045. if ($tokens->isPartialCodeMultiline($from, $until)) {
  88046. ++$this->deepestLevel;
  88047. $currentLevel = $this->currentLevel;
  88048. $this->currentLevel = $this->deepestLevel;
  88049. $this->injectAlignmentPlaceholdersForArrow($tokens, $from, $until);
  88050. $this->currentLevel = $currentLevel;
  88051. }
  88052. }
  88053. private function fixWhiteSpaceBeforeOperator(Tokens $tokens, int $index, string $alignStrategy): void
  88054. {
  88055. if (!$tokens[$index - 1]->isWhitespace()) {
  88056. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  88057. return;
  88058. }
  88059. if (
  88060. self::ALIGN_SINGLE_SPACE_MINIMAL !== $alignStrategy && self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE !== $alignStrategy
  88061. || $tokens[$tokens->getPrevNonWhitespace($index - 1)]->isComment()
  88062. ) {
  88063. return;
  88064. }
  88065. $content = $tokens[$index - 1]->getContent();
  88066. if (' ' !== $content && !str_contains($content, "\n")) {
  88067. $tokens[$index - 1] = new Token([T_WHITESPACE, ' ']);
  88068. }
  88069. }
  88070. private function replacePlaceholders(Tokens $tokens, string $alignStrategy, string $tokenContent): string
  88071. {
  88072. $tmpCode = $tokens->generateCode();
  88073. for ($j = 0; $j <= $this->deepestLevel; ++$j) {
  88074. $placeholder = \sprintf(self::ALIGN_PLACEHOLDER, $j);
  88075. if (!str_contains($tmpCode, $placeholder)) {
  88076. continue;
  88077. }
  88078. $lines = explode("\n", $tmpCode);
  88079. $groups = [];
  88080. $groupIndex = 0;
  88081. $groups[$groupIndex] = [];
  88082. foreach ($lines as $index => $line) {
  88083. if (substr_count($line, $placeholder) > 0) {
  88084. $groups[$groupIndex][] = $index;
  88085. } elseif (
  88086. self::ALIGN_BY_SCOPE !== $alignStrategy
  88087. && self::ALIGN_SINGLE_SPACE_BY_SCOPE !== $alignStrategy
  88088. && self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE !== $alignStrategy
  88089. ) {
  88090. ++$groupIndex;
  88091. $groups[$groupIndex] = [];
  88092. }
  88093. }
  88094. foreach ($groups as $group) {
  88095. if (\count($group) < 1) {
  88096. continue;
  88097. }
  88098. if (self::ALIGN !== $alignStrategy) {
  88099. foreach ($group as $index) {
  88100. $currentPosition = strpos($lines[$index], $placeholder);
  88101. $before = substr($lines[$index], 0, $currentPosition);
  88102. if (
  88103. self::ALIGN_SINGLE_SPACE === $alignStrategy
  88104. || self::ALIGN_SINGLE_SPACE_BY_SCOPE === $alignStrategy
  88105. ) {
  88106. if (!str_ends_with($before, ' ')) {
  88107. $before .= ' ';
  88108. }
  88109. } elseif (
  88110. self::ALIGN_SINGLE_SPACE_MINIMAL === $alignStrategy
  88111. || self::ALIGN_SINGLE_SPACE_MINIMAL_BY_SCOPE === $alignStrategy
  88112. ) {
  88113. if (!Preg::match('/^\h+$/', $before)) {
  88114. $before = rtrim($before).' ';
  88115. }
  88116. }
  88117. $lines[$index] = $before.substr($lines[$index], $currentPosition);
  88118. }
  88119. }
  88120. $rightmostSymbol = 0;
  88121. foreach ($group as $index) {
  88122. $rightmostSymbol = max($rightmostSymbol, $this->getSubstringWidth($lines[$index], $placeholder));
  88123. }
  88124. foreach ($group as $index) {
  88125. $line = $lines[$index];
  88126. $currentSymbol = $this->getSubstringWidth($line, $placeholder);
  88127. $delta = abs($rightmostSymbol - $currentSymbol);
  88128. if ($delta > 0) {
  88129. $line = str_replace($placeholder, str_repeat(' ', $delta).$placeholder, $line);
  88130. $lines[$index] = $line;
  88131. }
  88132. }
  88133. }
  88134. $tmpCode = str_replace($placeholder, '', implode("\n", $lines));
  88135. }
  88136. return $tmpCode;
  88137. }
  88138. private function getSubstringWidth(string $haystack, string $needle): int
  88139. {
  88140. $position = strpos($haystack, $needle);
  88141. \assert(\is_int($position));
  88142. $substring = substr($haystack, 0, $position);
  88143. return mb_strwidth($substring);
  88144. }
  88145. }
  88146. <?php
  88147. declare(strict_types=1);
  88148. namespace PhpCsFixer\Fixer\Operator;
  88149. use PhpCsFixer\AbstractFixer;
  88150. use PhpCsFixer\FixerDefinition\CodeSample;
  88151. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88152. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88153. use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
  88154. use PhpCsFixer\Tokenizer\Analyzer\GotoLabelAnalyzer;
  88155. use PhpCsFixer\Tokenizer\Analyzer\SwitchAnalyzer;
  88156. use PhpCsFixer\Tokenizer\Token;
  88157. use PhpCsFixer\Tokenizer\Tokens;
  88158. final class TernaryOperatorSpacesFixer extends AbstractFixer
  88159. {
  88160. public function getDefinition(): FixerDefinitionInterface
  88161. {
  88162. return new FixerDefinition(
  88163. 'Standardize spaces around ternary operator.',
  88164. [new CodeSample("<?php \$a = \$a ?1 :0;\n")]
  88165. );
  88166. }
  88167. public function getPriority(): int
  88168. {
  88169. return 1;
  88170. }
  88171. public function isCandidate(Tokens $tokens): bool
  88172. {
  88173. return $tokens->isAllTokenKindsFound(['?', ':']);
  88174. }
  88175. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88176. {
  88177. $alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
  88178. $gotoLabelAnalyzer = new GotoLabelAnalyzer();
  88179. $ternaryOperatorIndices = [];
  88180. foreach ($tokens as $index => $token) {
  88181. if (!$token->equalsAny(['?', ':'])) {
  88182. continue;
  88183. }
  88184. if (SwitchAnalyzer::belongsToSwitch($tokens, $index)) {
  88185. continue;
  88186. }
  88187. if ($alternativeSyntaxAnalyzer->belongsToAlternativeSyntax($tokens, $index)) {
  88188. continue;
  88189. }
  88190. if ($gotoLabelAnalyzer->belongsToGoToLabel($tokens, $index)) {
  88191. continue;
  88192. }
  88193. $ternaryOperatorIndices[] = $index;
  88194. }
  88195. foreach (array_reverse($ternaryOperatorIndices) as $index) {
  88196. $token = $tokens[$index];
  88197. if ($token->equals('?')) {
  88198. $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($index);
  88199. if ($tokens[$nextNonWhitespaceIndex]->equals(':')) {
  88200. $tokens->ensureWhitespaceAtIndex($index + 1, 0, '');
  88201. } else {
  88202. $this->ensureWhitespaceExistence($tokens, $index + 1, true);
  88203. }
  88204. $this->ensureWhitespaceExistence($tokens, $index - 1, false);
  88205. continue;
  88206. }
  88207. if ($token->equals(':')) {
  88208. $this->ensureWhitespaceExistence($tokens, $index + 1, true);
  88209. $prevNonWhitespaceToken = $tokens[$tokens->getPrevNonWhitespace($index)];
  88210. if (!$prevNonWhitespaceToken->equals('?')) {
  88211. $this->ensureWhitespaceExistence($tokens, $index - 1, false);
  88212. }
  88213. }
  88214. }
  88215. }
  88216. private function ensureWhitespaceExistence(Tokens $tokens, int $index, bool $after): void
  88217. {
  88218. if ($tokens[$index]->isWhitespace()) {
  88219. if (
  88220. !str_contains($tokens[$index]->getContent(), "\n")
  88221. && !$tokens[$index - 1]->isComment()
  88222. ) {
  88223. $tokens[$index] = new Token([T_WHITESPACE, ' ']);
  88224. }
  88225. return;
  88226. }
  88227. $index += $after ? 0 : 1;
  88228. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  88229. }
  88230. }
  88231. <?php
  88232. declare(strict_types=1);
  88233. namespace PhpCsFixer\Fixer\Operator;
  88234. use PhpCsFixer\AbstractFixer;
  88235. use PhpCsFixer\FixerDefinition\CodeSample;
  88236. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88237. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88238. use PhpCsFixer\Tokenizer\Token;
  88239. use PhpCsFixer\Tokenizer\Tokens;
  88240. final class TernaryToNullCoalescingFixer extends AbstractFixer
  88241. {
  88242. public function getDefinition(): FixerDefinitionInterface
  88243. {
  88244. return new FixerDefinition(
  88245. 'Use `null` coalescing operator `??` where possible.',
  88246. [
  88247. new CodeSample(
  88248. "<?php\n\$sample = isset(\$a) ? \$a : \$b;\n"
  88249. ),
  88250. ]
  88251. );
  88252. }
  88253. public function getPriority(): int
  88254. {
  88255. return 0;
  88256. }
  88257. public function isCandidate(Tokens $tokens): bool
  88258. {
  88259. return $tokens->isTokenKindFound(T_ISSET);
  88260. }
  88261. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88262. {
  88263. $issetIndices = array_keys($tokens->findGivenKind(T_ISSET));
  88264. foreach (array_reverse($issetIndices) as $issetIndex) {
  88265. $this->fixIsset($tokens, $issetIndex);
  88266. }
  88267. }
  88268. private function fixIsset(Tokens $tokens, int $index): void
  88269. {
  88270. $prevTokenIndex = $tokens->getPrevMeaningfulToken($index);
  88271. if ($this->isHigherPrecedenceAssociativityOperator($tokens[$prevTokenIndex])) {
  88272. return;
  88273. }
  88274. $startBraceIndex = $tokens->getNextTokenOfKind($index, ['(']);
  88275. $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startBraceIndex);
  88276. $ternaryQuestionMarkIndex = $tokens->getNextMeaningfulToken($endBraceIndex);
  88277. if (!$tokens[$ternaryQuestionMarkIndex]->equals('?')) {
  88278. return;
  88279. }
  88280. $issetTokens = $this->getMeaningfulSequence($tokens, $startBraceIndex, $endBraceIndex);
  88281. if ($this->hasChangingContent($issetTokens)) {
  88282. return;
  88283. }
  88284. $issetCode = $issetTokens->generateCode();
  88285. if ('$this' === $issetCode) {
  88286. return;
  88287. }
  88288. $ternaryColonIndex = $tokens->getNextTokenOfKind($ternaryQuestionMarkIndex, [':']);
  88289. $ternaryFirstOperandTokens = $this->getMeaningfulSequence($tokens, $ternaryQuestionMarkIndex, $ternaryColonIndex);
  88290. if ($issetCode !== $ternaryFirstOperandTokens->generateCode()) {
  88291. return;
  88292. }
  88293. $ternaryFirstOperandIndex = $tokens->getNextMeaningfulToken($ternaryQuestionMarkIndex);
  88294. $comments = [];
  88295. $commentStarted = false;
  88296. for ($loopIndex = $index; $loopIndex < $ternaryFirstOperandIndex; ++$loopIndex) {
  88297. if ($tokens[$loopIndex]->isComment()) {
  88298. $comments[] = $tokens[$loopIndex];
  88299. $commentStarted = true;
  88300. } elseif ($commentStarted) {
  88301. if ($tokens[$loopIndex]->isWhitespace()) {
  88302. $comments[] = $tokens[$loopIndex];
  88303. }
  88304. $commentStarted = false;
  88305. }
  88306. }
  88307. $tokens[$ternaryColonIndex] = new Token([T_COALESCE, '??']);
  88308. $tokens->overrideRange($index, $ternaryFirstOperandIndex - 1, $comments);
  88309. }
  88310. private function getMeaningfulSequence(Tokens $tokens, int $start, int $end): Tokens
  88311. {
  88312. $sequence = [];
  88313. $index = $start;
  88314. while ($index < $end) {
  88315. $index = $tokens->getNextMeaningfulToken($index);
  88316. if ($index >= $end || null === $index) {
  88317. break;
  88318. }
  88319. $sequence[] = $tokens[$index];
  88320. }
  88321. return Tokens::fromArray($sequence);
  88322. }
  88323. private function isHigherPrecedenceAssociativityOperator(Token $token): bool
  88324. {
  88325. static $operatorsPerId = [
  88326. T_ARRAY_CAST => true,
  88327. T_BOOLEAN_AND => true,
  88328. T_BOOLEAN_OR => true,
  88329. T_BOOL_CAST => true,
  88330. T_COALESCE => true,
  88331. T_DEC => true,
  88332. T_DOUBLE_CAST => true,
  88333. T_INC => true,
  88334. T_INT_CAST => true,
  88335. T_IS_EQUAL => true,
  88336. T_IS_GREATER_OR_EQUAL => true,
  88337. T_IS_IDENTICAL => true,
  88338. T_IS_NOT_EQUAL => true,
  88339. T_IS_NOT_IDENTICAL => true,
  88340. T_IS_SMALLER_OR_EQUAL => true,
  88341. T_OBJECT_CAST => true,
  88342. T_POW => true,
  88343. T_SL => true,
  88344. T_SPACESHIP => true,
  88345. T_SR => true,
  88346. T_STRING_CAST => true,
  88347. T_UNSET_CAST => true,
  88348. ];
  88349. static $operatorsPerContent = [
  88350. '!',
  88351. '%',
  88352. '&',
  88353. '*',
  88354. '+',
  88355. '-',
  88356. '/',
  88357. ':',
  88358. '^',
  88359. '|',
  88360. '~',
  88361. '.',
  88362. ];
  88363. return isset($operatorsPerId[$token->getId()]) || $token->equalsAny($operatorsPerContent);
  88364. }
  88365. private function hasChangingContent(Tokens $tokens): bool
  88366. {
  88367. static $operatorsPerId = [
  88368. T_DEC,
  88369. T_INC,
  88370. T_YIELD,
  88371. T_YIELD_FROM,
  88372. ];
  88373. foreach ($tokens as $token) {
  88374. if ($token->isGivenKind($operatorsPerId) || $token->equals('(')) {
  88375. return true;
  88376. }
  88377. }
  88378. return false;
  88379. }
  88380. }
  88381. <?php
  88382. declare(strict_types=1);
  88383. namespace PhpCsFixer\Fixer\Operator;
  88384. use PhpCsFixer\AbstractFixer;
  88385. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  88386. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  88387. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  88388. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  88389. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  88390. use PhpCsFixer\FixerDefinition\CodeSample;
  88391. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88392. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88393. use PhpCsFixer\Tokenizer\Tokens;
  88394. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  88395. /**
  88396. @phpstan-type
  88397. @phpstan-type
  88398. @implements
  88399. */
  88400. final class UnaryOperatorSpacesFixer extends AbstractFixer implements ConfigurableFixerInterface
  88401. {
  88402. /**
  88403. @use */
  88404. use ConfigurableFixerTrait;
  88405. public function getDefinition(): FixerDefinitionInterface
  88406. {
  88407. return new FixerDefinition(
  88408. 'Unary operators should be placed adjacent to their operands.',
  88409. [
  88410. new CodeSample("<?php\n\$sample ++;\n-- \$sample;\n\$sample = ! ! \$a;\n\$sample = ~ \$c;\nfunction & foo(){}\n"),
  88411. new CodeSample(
  88412. '<?php
  88413. function foo($a, ... $b) { return (-- $a) * ($b ++);}
  88414. ',
  88415. ['only_dec_inc' => false]
  88416. ),
  88417. new CodeSample(
  88418. '<?php
  88419. function foo($a, ... $b) { return (-- $a) * ($b ++);}
  88420. ',
  88421. ['only_dec_inc' => true]
  88422. ),
  88423. ]
  88424. );
  88425. }
  88426. public function getPriority(): int
  88427. {
  88428. return 0;
  88429. }
  88430. public function isCandidate(Tokens $tokens): bool
  88431. {
  88432. return true;
  88433. }
  88434. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  88435. {
  88436. return new FixerConfigurationResolver([
  88437. (new FixerOptionBuilder('only_dec_inc', 'Limit to increment and decrement operators.'))
  88438. ->setAllowedTypes(['bool'])
  88439. ->setDefault(false)
  88440. ->getOption(),
  88441. ]);
  88442. }
  88443. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88444. {
  88445. $tokensAnalyzer = new TokensAnalyzer($tokens);
  88446. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  88447. if (true === $this->configuration['only_dec_inc'] && !$tokens[$index]->isGivenKind([T_DEC, T_INC])) {
  88448. continue;
  88449. }
  88450. if ($tokensAnalyzer->isUnarySuccessorOperator($index)) {
  88451. if (!$tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
  88452. $tokens->removeLeadingWhitespace($index);
  88453. }
  88454. continue;
  88455. }
  88456. if ($tokensAnalyzer->isUnaryPredecessorOperator($index)) {
  88457. $tokens->removeTrailingWhitespace($index);
  88458. continue;
  88459. }
  88460. }
  88461. }
  88462. }
  88463. <?php
  88464. declare(strict_types=1);
  88465. namespace PhpCsFixer\Fixer\Operator;
  88466. use PhpCsFixer\AbstractFixer;
  88467. use PhpCsFixer\FixerDefinition\CodeSample;
  88468. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88469. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88470. use PhpCsFixer\Tokenizer\Analyzer\RangeAnalyzer;
  88471. use PhpCsFixer\Tokenizer\CT;
  88472. use PhpCsFixer\Tokenizer\Tokens;
  88473. final class TernaryToElvisOperatorFixer extends AbstractFixer
  88474. {
  88475. private const VALID_BEFORE_ENDTYPES = [
  88476. '=',
  88477. [T_OPEN_TAG],
  88478. [T_OPEN_TAG_WITH_ECHO],
  88479. '(',
  88480. ',',
  88481. ';',
  88482. '[',
  88483. '{',
  88484. '}',
  88485. [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN],
  88486. [T_AND_EQUAL],
  88487. [T_CONCAT_EQUAL],
  88488. [T_DIV_EQUAL],
  88489. [T_MINUS_EQUAL],
  88490. [T_MOD_EQUAL],
  88491. [T_MUL_EQUAL],
  88492. [T_OR_EQUAL],
  88493. [T_PLUS_EQUAL],
  88494. [T_POW_EQUAL],
  88495. [T_SL_EQUAL],
  88496. [T_SR_EQUAL],
  88497. [T_XOR_EQUAL],
  88498. ];
  88499. public function getDefinition(): FixerDefinitionInterface
  88500. {
  88501. return new FixerDefinition(
  88502. 'Use the Elvis operator `?:` where possible.',
  88503. [
  88504. new CodeSample(
  88505. "<?php\n\$foo = \$foo ? \$foo : 1;\n"
  88506. ),
  88507. new CodeSample(
  88508. "<?php \$foo = \$bar[a()] ? \$bar[a()] : 1; # \"risky\" sample, \"a()\" only gets called once after fixing\n"
  88509. ),
  88510. ],
  88511. null,
  88512. 'Risky when relying on functions called on both sides of the `?` operator.'
  88513. );
  88514. }
  88515. public function getPriority(): int
  88516. {
  88517. return 2;
  88518. }
  88519. public function isCandidate(Tokens $tokens): bool
  88520. {
  88521. return $tokens->isTokenKindFound('?');
  88522. }
  88523. public function isRisky(): bool
  88524. {
  88525. return true;
  88526. }
  88527. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88528. {
  88529. for ($index = \count($tokens) - 5; $index > 1; --$index) {
  88530. if (!$tokens[$index]->equals('?')) {
  88531. continue;
  88532. }
  88533. $nextIndex = $tokens->getNextMeaningfulToken($index);
  88534. if ($tokens[$nextIndex]->equals(':')) {
  88535. continue;
  88536. }
  88537. $beforeOperator = $this->getBeforeOperator($tokens, $index);
  88538. if (null === $beforeOperator) {
  88539. continue;
  88540. }
  88541. $afterOperator = $this->getAfterOperator($tokens, $index);
  88542. if (RangeAnalyzer::rangeEqualsRange($tokens, $beforeOperator, $afterOperator)) {
  88543. $this->clearMeaningfulFromRange($tokens, $afterOperator);
  88544. }
  88545. }
  88546. }
  88547. private function getBeforeOperator(Tokens $tokens, int $index): ?array
  88548. {
  88549. $blockEdgeDefinitions = Tokens::getBlockEdgeDefinitions();
  88550. $index = $tokens->getPrevMeaningfulToken($index);
  88551. $before = ['end' => $index];
  88552. while (!$tokens[$index]->equalsAny(self::VALID_BEFORE_ENDTYPES)) {
  88553. if ($tokens[$index]->isGivenKind([T_INC, T_DEC])) {
  88554. return null;
  88555. }
  88556. $detectedBlockType = Tokens::detectBlockType($tokens[$index]);
  88557. if (null === $detectedBlockType || $detectedBlockType['isStart']) {
  88558. $before['start'] = $index;
  88559. $index = $tokens->getPrevMeaningfulToken($index);
  88560. continue;
  88561. }
  88562. /**
  88563. @phpstan-ignore-next-line */
  88564. $blockType = $blockEdgeDefinitions[$detectedBlockType['type']];
  88565. $openCount = 1;
  88566. do {
  88567. $index = $tokens->getPrevMeaningfulToken($index);
  88568. if ($tokens[$index]->isGivenKind([T_INC, T_DEC])) {
  88569. return null;
  88570. }
  88571. if ($tokens[$index]->equals($blockType['start'])) {
  88572. ++$openCount;
  88573. continue;
  88574. }
  88575. if ($tokens[$index]->equals($blockType['end'])) {
  88576. --$openCount;
  88577. }
  88578. } while (1 >= $openCount);
  88579. $before['start'] = $index;
  88580. $index = $tokens->getPrevMeaningfulToken($index);
  88581. }
  88582. if (!isset($before['start'])) {
  88583. return null;
  88584. }
  88585. return $before;
  88586. }
  88587. private function getAfterOperator(Tokens $tokens, int $index): array
  88588. {
  88589. $index = $tokens->getNextMeaningfulToken($index);
  88590. $after = ['start' => $index];
  88591. do {
  88592. $blockType = Tokens::detectBlockType($tokens[$index]);
  88593. if (null !== $blockType) {
  88594. $index = $tokens->findBlockEnd($blockType['type'], $index);
  88595. }
  88596. $after['end'] = $index;
  88597. $index = $tokens->getNextMeaningfulToken($index);
  88598. } while (!$tokens[$index]->equals(':'));
  88599. return $after;
  88600. }
  88601. private function clearMeaningfulFromRange(Tokens $tokens, array $range): void
  88602. {
  88603. for ($i = $range['end']; $i >= $range['start']; $i = $tokens->getPrevMeaningfulToken($i)) {
  88604. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  88605. }
  88606. }
  88607. }
  88608. <?php
  88609. declare(strict_types=1);
  88610. namespace PhpCsFixer\Fixer\Operator;
  88611. use PhpCsFixer\Fixer\AbstractIncrementOperatorFixer;
  88612. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  88613. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  88614. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  88615. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  88616. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  88617. use PhpCsFixer\FixerDefinition\CodeSample;
  88618. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88619. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88620. use PhpCsFixer\Tokenizer\CT;
  88621. use PhpCsFixer\Tokenizer\Tokens;
  88622. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  88623. /**
  88624. @phpstan-type
  88625. @phpstan-type
  88626. @implements
  88627. */
  88628. final class IncrementStyleFixer extends AbstractIncrementOperatorFixer implements ConfigurableFixerInterface
  88629. {
  88630. /**
  88631. @use */
  88632. use ConfigurableFixerTrait;
  88633. public const STYLE_PRE = 'pre';
  88634. public const STYLE_POST = 'post';
  88635. public function getDefinition(): FixerDefinitionInterface
  88636. {
  88637. return new FixerDefinition(
  88638. 'Pre- or post-increment and decrement operators should be used if possible.',
  88639. [
  88640. new CodeSample("<?php\n\$a++;\n\$b--;\n"),
  88641. new CodeSample(
  88642. "<?php\n++\$a;\n--\$b;\n",
  88643. ['style' => self::STYLE_POST]
  88644. ),
  88645. ]
  88646. );
  88647. }
  88648. public function getPriority(): int
  88649. {
  88650. return 15;
  88651. }
  88652. public function isCandidate(Tokens $tokens): bool
  88653. {
  88654. return $tokens->isAnyTokenKindsFound([T_INC, T_DEC]);
  88655. }
  88656. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  88657. {
  88658. return new FixerConfigurationResolver([
  88659. (new FixerOptionBuilder('style', 'Whether to use pre- or post-increment and decrement operators.'))
  88660. ->setAllowedValues([self::STYLE_PRE, self::STYLE_POST])
  88661. ->setDefault(self::STYLE_PRE)
  88662. ->getOption(),
  88663. ]);
  88664. }
  88665. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88666. {
  88667. $tokensAnalyzer = new TokensAnalyzer($tokens);
  88668. for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
  88669. $token = $tokens[$index];
  88670. if (!$token->isGivenKind([T_INC, T_DEC])) {
  88671. continue;
  88672. }
  88673. if (self::STYLE_PRE === $this->configuration['style'] && $tokensAnalyzer->isUnarySuccessorOperator($index)) {
  88674. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  88675. if (!$nextToken->equalsAny([';', ')'])) {
  88676. continue;
  88677. }
  88678. $startIndex = $this->findStart($tokens, $index);
  88679. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($startIndex)];
  88680. if ($prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG], ')'])) {
  88681. $tokens->clearAt($index);
  88682. $tokens->insertAt($startIndex, clone $token);
  88683. }
  88684. } elseif (self::STYLE_POST === $this->configuration['style'] && $tokensAnalyzer->isUnaryPredecessorOperator($index)) {
  88685. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  88686. if (!$prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG], ')'])) {
  88687. continue;
  88688. }
  88689. $endIndex = $this->findEnd($tokens, $index);
  88690. $nextToken = $tokens[$tokens->getNextMeaningfulToken($endIndex)];
  88691. if ($nextToken->equalsAny([';', ')'])) {
  88692. $tokens->clearAt($index);
  88693. $tokens->insertAt($tokens->getNextNonWhitespace($endIndex), clone $token);
  88694. }
  88695. }
  88696. }
  88697. }
  88698. private function findEnd(Tokens $tokens, int $index): int
  88699. {
  88700. $nextIndex = $tokens->getNextMeaningfulToken($index);
  88701. $nextToken = $tokens[$nextIndex];
  88702. while ($nextToken->equalsAny([
  88703. '$',
  88704. '(',
  88705. '[',
  88706. [CT::T_DYNAMIC_PROP_BRACE_OPEN],
  88707. [CT::T_DYNAMIC_VAR_BRACE_OPEN],
  88708. [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN],
  88709. [T_NS_SEPARATOR],
  88710. [T_STATIC],
  88711. [T_STRING],
  88712. [T_VARIABLE],
  88713. ])) {
  88714. $blockType = Tokens::detectBlockType($nextToken);
  88715. if (null !== $blockType) {
  88716. $nextIndex = $tokens->findBlockEnd($blockType['type'], $nextIndex);
  88717. }
  88718. $index = $nextIndex;
  88719. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  88720. $nextToken = $tokens[$nextIndex];
  88721. }
  88722. if ($nextToken->isObjectOperator()) {
  88723. return $this->findEnd($tokens, $nextIndex);
  88724. }
  88725. if ($nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
  88726. return $this->findEnd($tokens, $tokens->getNextMeaningfulToken($nextIndex));
  88727. }
  88728. return $index;
  88729. }
  88730. }
  88731. <?php
  88732. declare(strict_types=1);
  88733. namespace PhpCsFixer\Fixer\Operator;
  88734. use PhpCsFixer\AbstractFixer;
  88735. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  88736. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  88737. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  88738. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  88739. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  88740. use PhpCsFixer\FixerDefinition\CodeSample;
  88741. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88742. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88743. use PhpCsFixer\Preg;
  88744. use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
  88745. use PhpCsFixer\Tokenizer\Analyzer\GotoLabelAnalyzer;
  88746. use PhpCsFixer\Tokenizer\Analyzer\ReferenceAnalyzer;
  88747. use PhpCsFixer\Tokenizer\Analyzer\SwitchAnalyzer;
  88748. use PhpCsFixer\Tokenizer\Token;
  88749. use PhpCsFixer\Tokenizer\Tokens;
  88750. /**
  88751. @phpstan-type
  88752. @phpstan-type
  88753. @implements
  88754. */
  88755. final class OperatorLinebreakFixer extends AbstractFixer implements ConfigurableFixerInterface
  88756. {
  88757. /**
  88758. @use */
  88759. use ConfigurableFixerTrait;
  88760. private const BOOLEAN_OPERATORS = [[T_BOOLEAN_AND], [T_BOOLEAN_OR], [T_LOGICAL_AND], [T_LOGICAL_OR], [T_LOGICAL_XOR]];
  88761. private string $position = 'beginning';
  88762. private array $operators = [];
  88763. public function getDefinition(): FixerDefinitionInterface
  88764. {
  88765. return new FixerDefinition(
  88766. 'Operators - when multiline - must always be at the beginning or at the end of the line.',
  88767. [
  88768. new CodeSample('<?php
  88769. function foo() {
  88770. return $bar ||
  88771. $baz;
  88772. }
  88773. '),
  88774. new CodeSample(
  88775. '<?php
  88776. function foo() {
  88777. return $bar
  88778. || $baz;
  88779. }
  88780. ',
  88781. ['position' => 'end']
  88782. ),
  88783. ]
  88784. );
  88785. }
  88786. public function isCandidate(Tokens $tokens): bool
  88787. {
  88788. return true;
  88789. }
  88790. protected function configurePostNormalisation(): void
  88791. {
  88792. $this->position = $this->configuration['position'];
  88793. $this->operators = self::BOOLEAN_OPERATORS;
  88794. if (false === $this->configuration['only_booleans']) {
  88795. $this->operators = array_merge($this->operators, self::getNonBooleanOperators());
  88796. }
  88797. }
  88798. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  88799. {
  88800. return new FixerConfigurationResolver([
  88801. (new FixerOptionBuilder('only_booleans', 'Whether to limit operators to only boolean ones.'))
  88802. ->setAllowedTypes(['bool'])
  88803. ->setDefault(false)
  88804. ->getOption(),
  88805. (new FixerOptionBuilder('position', 'Whether to place operators at the beginning or at the end of the line.'))
  88806. ->setAllowedValues(['beginning', 'end'])
  88807. ->setDefault($this->position)
  88808. ->getOption(),
  88809. ]);
  88810. }
  88811. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  88812. {
  88813. $referenceAnalyzer = new ReferenceAnalyzer();
  88814. $gotoLabelAnalyzer = new GotoLabelAnalyzer();
  88815. $alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
  88816. $index = $tokens->count();
  88817. while ($index > 1) {
  88818. --$index;
  88819. if (!$tokens[$index]->equalsAny($this->operators, false)) {
  88820. continue;
  88821. }
  88822. if ($gotoLabelAnalyzer->belongsToGoToLabel($tokens, $index)) {
  88823. continue;
  88824. }
  88825. if ($referenceAnalyzer->isReference($tokens, $index)) {
  88826. continue;
  88827. }
  88828. if ($alternativeSyntaxAnalyzer->belongsToAlternativeSyntax($tokens, $index)) {
  88829. continue;
  88830. }
  88831. if (SwitchAnalyzer::belongsToSwitch($tokens, $index)) {
  88832. continue;
  88833. }
  88834. $operatorIndices = [$index];
  88835. if ($tokens[$index]->equals(':')) {
  88836. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  88837. if ($tokens[$prevIndex]->equals('?')) {
  88838. $operatorIndices = [$prevIndex, $index];
  88839. $index = $prevIndex;
  88840. }
  88841. }
  88842. $this->fixOperatorLinebreak($tokens, $operatorIndices);
  88843. }
  88844. }
  88845. private function fixOperatorLinebreak(Tokens $tokens, array $operatorIndices): void
  88846. {
  88847. $prevIndex = $tokens->getPrevMeaningfulToken(min($operatorIndices));
  88848. $indexStart = $prevIndex + 1;
  88849. $nextIndex = $tokens->getNextMeaningfulToken(max($operatorIndices));
  88850. $indexEnd = $nextIndex - 1;
  88851. if (!$this->isMultiline($tokens, $indexStart, $indexEnd)) {
  88852. return;
  88853. }
  88854. if ('beginning' === $this->position) {
  88855. if (!$this->isMultiline($tokens, max($operatorIndices), $indexEnd)) {
  88856. return;
  88857. }
  88858. $this->fixMoveToTheBeginning($tokens, $operatorIndices);
  88859. return;
  88860. }
  88861. if (!$this->isMultiline($tokens, $indexStart, min($operatorIndices))) {
  88862. return;
  88863. }
  88864. $this->fixMoveToTheEnd($tokens, $operatorIndices);
  88865. }
  88866. private function fixMoveToTheBeginning(Tokens $tokens, array $operatorIndices): void
  88867. {
  88868. $prevIndex = $tokens->getNonEmptySibling(min($operatorIndices), -1);
  88869. $nextIndex = $tokens->getNextMeaningfulToken(max($operatorIndices));
  88870. for ($i = $nextIndex - 1; $i > max($operatorIndices); --$i) {
  88871. if ($tokens[$i]->isWhitespace() && Preg::match('/\R/u', $tokens[$i]->getContent())) {
  88872. $isWhitespaceBefore = $tokens[$prevIndex]->isWhitespace();
  88873. $inserts = $this->getReplacementsAndClear($tokens, $operatorIndices, -1);
  88874. if ($isWhitespaceBefore) {
  88875. $inserts[] = new Token([T_WHITESPACE, ' ']);
  88876. }
  88877. $tokens->insertAt($nextIndex, $inserts);
  88878. break;
  88879. }
  88880. }
  88881. }
  88882. private function fixMoveToTheEnd(Tokens $tokens, array $operatorIndices): void
  88883. {
  88884. $prevIndex = $tokens->getPrevMeaningfulToken(min($operatorIndices));
  88885. $nextIndex = $tokens->getNonEmptySibling(max($operatorIndices), 1);
  88886. for ($i = $prevIndex + 1; $i < max($operatorIndices); ++$i) {
  88887. if ($tokens[$i]->isWhitespace() && Preg::match('/\R/u', $tokens[$i]->getContent())) {
  88888. $isWhitespaceAfter = $tokens[$nextIndex]->isWhitespace();
  88889. $inserts = $this->getReplacementsAndClear($tokens, $operatorIndices, 1);
  88890. if ($isWhitespaceAfter) {
  88891. array_unshift($inserts, new Token([T_WHITESPACE, ' ']));
  88892. }
  88893. $tokens->insertAt($prevIndex + 1, $inserts);
  88894. break;
  88895. }
  88896. }
  88897. }
  88898. private function getReplacementsAndClear(Tokens $tokens, array $indices, int $direction): array
  88899. {
  88900. return array_map(
  88901. static function (int $index) use ($tokens, $direction): Token {
  88902. $clone = $tokens[$index];
  88903. if ($tokens[$index + $direction]->isWhitespace()) {
  88904. $tokens->clearAt($index + $direction);
  88905. }
  88906. $tokens->clearAt($index);
  88907. return $clone;
  88908. },
  88909. $indices
  88910. );
  88911. }
  88912. private function isMultiline(Tokens $tokens, int $indexStart, int $indexEnd): bool
  88913. {
  88914. for ($index = $indexStart; $index <= $indexEnd; ++$index) {
  88915. if (str_contains($tokens[$index]->getContent(), "\n")) {
  88916. return true;
  88917. }
  88918. }
  88919. return false;
  88920. }
  88921. private static function getNonBooleanOperators(): array
  88922. {
  88923. return array_merge(
  88924. [
  88925. '%', '&', '*', '+', '-', '.', '/', ':', '<', '=', '>', '?', '^', '|',
  88926. [T_AND_EQUAL], [T_CONCAT_EQUAL], [T_DIV_EQUAL], [T_DOUBLE_ARROW], [T_IS_EQUAL], [T_IS_GREATER_OR_EQUAL],
  88927. [T_IS_IDENTICAL], [T_IS_NOT_EQUAL], [T_IS_NOT_IDENTICAL], [T_IS_SMALLER_OR_EQUAL], [T_MINUS_EQUAL],
  88928. [T_MOD_EQUAL], [T_MUL_EQUAL], [T_OR_EQUAL], [T_PAAMAYIM_NEKUDOTAYIM], [T_PLUS_EQUAL], [T_POW],
  88929. [T_POW_EQUAL], [T_SL], [T_SL_EQUAL], [T_SR], [T_SR_EQUAL], [T_XOR_EQUAL],
  88930. [T_COALESCE], [T_SPACESHIP],
  88931. ],
  88932. array_map(static fn (int $id): array => [$id], Token::getObjectOperatorKinds()),
  88933. );
  88934. }
  88935. }
  88936. <?php
  88937. declare(strict_types=1);
  88938. namespace PhpCsFixer\Fixer\Operator;
  88939. use PhpCsFixer\AbstractFixer;
  88940. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  88941. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  88942. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  88943. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  88944. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  88945. use PhpCsFixer\FixerDefinition\CodeSample;
  88946. use PhpCsFixer\FixerDefinition\FixerDefinition;
  88947. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  88948. use PhpCsFixer\Tokenizer\CT;
  88949. use PhpCsFixer\Tokenizer\FCT;
  88950. use PhpCsFixer\Tokenizer\Token;
  88951. use PhpCsFixer\Tokenizer\Tokens;
  88952. /**
  88953. @phpstan-type
  88954. @phpstan-type
  88955. @implements
  88956. */
  88957. final class NewWithParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
  88958. {
  88959. /**
  88960. @use */
  88961. use ConfigurableFixerTrait;
  88962. private const NEXT_TOKEN_KINDS = [
  88963. '?',
  88964. ';',
  88965. ',',
  88966. '(',
  88967. ')',
  88968. '[',
  88969. ']',
  88970. ':',
  88971. '<',
  88972. '>',
  88973. '+',
  88974. '-',
  88975. '*',
  88976. '/',
  88977. '%',
  88978. '&',
  88979. '^',
  88980. '|',
  88981. [T_CLASS],
  88982. [T_IS_SMALLER_OR_EQUAL],
  88983. [T_IS_GREATER_OR_EQUAL],
  88984. [T_IS_EQUAL],
  88985. [T_IS_NOT_EQUAL],
  88986. [T_IS_IDENTICAL],
  88987. [T_IS_NOT_IDENTICAL],
  88988. [T_CLOSE_TAG],
  88989. [T_LOGICAL_AND],
  88990. [T_LOGICAL_OR],
  88991. [T_LOGICAL_XOR],
  88992. [T_BOOLEAN_AND],
  88993. [T_BOOLEAN_OR],
  88994. [T_SL],
  88995. [T_SR],
  88996. [T_INSTANCEOF],
  88997. [T_AS],
  88998. [T_DOUBLE_ARROW],
  88999. [T_POW],
  89000. [T_SPACESHIP],
  89001. [CT::T_ARRAY_SQUARE_BRACE_OPEN],
  89002. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  89003. [CT::T_BRACE_CLASS_INSTANTIATION_OPEN],
  89004. [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
  89005. [FCT::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG],
  89006. [FCT::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG],
  89007. ];
  89008. public function getDefinition(): FixerDefinitionInterface
  89009. {
  89010. return new FixerDefinition(
  89011. 'All instances created with `new` keyword must (not) be followed by parentheses.',
  89012. [
  89013. new CodeSample("<?php\n\n\$x = new X;\n\$y = new class {};\n"),
  89014. new CodeSample(
  89015. "<?php\n\n\$y = new class() {};\n",
  89016. ['anonymous_class' => false]
  89017. ),
  89018. new CodeSample(
  89019. "<?php\n\n\$x = new X();\n",
  89020. ['named_class' => false]
  89021. ),
  89022. ]
  89023. );
  89024. }
  89025. public function getPriority(): int
  89026. {
  89027. return 38;
  89028. }
  89029. public function isCandidate(Tokens $tokens): bool
  89030. {
  89031. return $tokens->isTokenKindFound(T_NEW);
  89032. }
  89033. /**
  89034. @protected */
  89035. public function createConfigurationDefinition(): FixerConfigurationResolverInterface
  89036. {
  89037. return new FixerConfigurationResolver([
  89038. (new FixerOptionBuilder('named_class', 'Whether named classes should be followed by parentheses.'))
  89039. ->setAllowedTypes(['bool'])
  89040. ->setDefault(true)
  89041. ->getOption(),
  89042. (new FixerOptionBuilder('anonymous_class', 'Whether anonymous classes should be followed by parentheses.'))
  89043. ->setAllowedTypes(['bool'])
  89044. ->setDefault(true)
  89045. ->getOption(),
  89046. ]);
  89047. }
  89048. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89049. {
  89050. for ($index = $tokens->count() - 3; $index > 0; --$index) {
  89051. if (!$tokens[$index]->isGivenKind(T_NEW)) {
  89052. continue;
  89053. }
  89054. $nextIndex = $tokens->getNextTokenOfKind($index, self::NEXT_TOKEN_KINDS);
  89055. if ($tokens[$nextIndex]->isGivenKind(T_CLASS)) {
  89056. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  89057. if (true === $this->configuration['anonymous_class']) {
  89058. $this->ensureParenthesesAt($tokens, $nextIndex);
  89059. } else {
  89060. $this->ensureNoParenthesesAt($tokens, $nextIndex);
  89061. }
  89062. continue;
  89063. }
  89064. while ($tokens[$nextIndex]->equals('[') || $tokens[$nextIndex]->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
  89065. $nextIndex = $tokens->findBlockEnd(Tokens::detectBlockType($tokens[$nextIndex])['type'], $nextIndex);
  89066. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  89067. }
  89068. if (true === $this->configuration['named_class']) {
  89069. $this->ensureParenthesesAt($tokens, $nextIndex);
  89070. } else {
  89071. $this->ensureNoParenthesesAt($tokens, $nextIndex);
  89072. }
  89073. }
  89074. }
  89075. private function ensureParenthesesAt(Tokens $tokens, int $index): void
  89076. {
  89077. $token = $tokens[$index];
  89078. if (!$token->equals('(') && !$token->isObjectOperator()) {
  89079. $tokens->insertAt(
  89080. $tokens->getPrevMeaningfulToken($index) + 1,
  89081. [new Token('('), new Token(')')]
  89082. );
  89083. }
  89084. }
  89085. private function ensureNoParenthesesAt(Tokens $tokens, int $index): void
  89086. {
  89087. if (!$tokens[$index]->equals('(')) {
  89088. return;
  89089. }
  89090. $closingIndex = $tokens->getNextMeaningfulToken($index);
  89091. if (!$tokens[$closingIndex]->equals(')')) {
  89092. return;
  89093. }
  89094. $afterClosingIndex = $tokens->getNextMeaningfulToken($closingIndex);
  89095. if ($tokens[$afterClosingIndex]->isObjectOperator()) {
  89096. return;
  89097. }
  89098. $tokens->clearTokenAndMergeSurroundingWhitespace($closingIndex);
  89099. $tokens->clearTokenAndMergeSurroundingWhitespace($index);
  89100. }
  89101. }
  89102. <?php
  89103. declare(strict_types=1);
  89104. namespace PhpCsFixer\Fixer\Operator;
  89105. use PhpCsFixer\AbstractFixer;
  89106. use PhpCsFixer\FixerDefinition\CodeSample;
  89107. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89108. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89109. use PhpCsFixer\Tokenizer\Token;
  89110. use PhpCsFixer\Tokenizer\Tokens;
  89111. final class LogicalOperatorsFixer extends AbstractFixer
  89112. {
  89113. public function getDefinition(): FixerDefinitionInterface
  89114. {
  89115. return new FixerDefinition(
  89116. 'Use `&&` and `||` logical operators instead of `and` and `or`.',
  89117. [
  89118. new CodeSample(
  89119. '<?php
  89120. if ($a == "foo" and ($b == "bar" or $c == "baz")) {
  89121. }
  89122. '
  89123. ),
  89124. ],
  89125. null,
  89126. 'Risky, because you must double-check if using and/or with lower precedence was intentional.'
  89127. );
  89128. }
  89129. public function isCandidate(Tokens $tokens): bool
  89130. {
  89131. return $tokens->isAnyTokenKindsFound([T_LOGICAL_AND, T_LOGICAL_OR]);
  89132. }
  89133. public function isRisky(): bool
  89134. {
  89135. return true;
  89136. }
  89137. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89138. {
  89139. foreach ($tokens as $index => $token) {
  89140. if ($token->isGivenKind(T_LOGICAL_AND)) {
  89141. $tokens[$index] = new Token([T_BOOLEAN_AND, '&&']);
  89142. } elseif ($token->isGivenKind(T_LOGICAL_OR)) {
  89143. $tokens[$index] = new Token([T_BOOLEAN_OR, '||']);
  89144. }
  89145. }
  89146. }
  89147. }
  89148. <?php
  89149. declare(strict_types=1);
  89150. namespace PhpCsFixer\Fixer\Operator;
  89151. use PhpCsFixer\AbstractProxyFixer;
  89152. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  89153. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  89154. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  89155. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  89156. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89157. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89158. /**
  89159. @phpstan-type
  89160. @phpstan-type
  89161. @implements
  89162. */
  89163. final class NewWithBracesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface
  89164. {
  89165. /**
  89166. @use */
  89167. use ConfigurableFixerTrait;
  89168. private NewWithParenthesesFixer $newWithParenthesesFixer;
  89169. public function __construct()
  89170. {
  89171. $this->newWithParenthesesFixer = new NewWithParenthesesFixer();
  89172. parent::__construct();
  89173. }
  89174. public function getDefinition(): FixerDefinitionInterface
  89175. {
  89176. $fixerDefinition = $this->newWithParenthesesFixer->getDefinition();
  89177. return new FixerDefinition(
  89178. 'All instances created with `new` keyword must (not) be followed by braces.',
  89179. $fixerDefinition->getCodeSamples(),
  89180. $fixerDefinition->getDescription(),
  89181. $fixerDefinition->getRiskyDescription(),
  89182. );
  89183. }
  89184. public function getPriority(): int
  89185. {
  89186. return $this->newWithParenthesesFixer->getPriority();
  89187. }
  89188. public function getSuccessorsNames(): array
  89189. {
  89190. return [
  89191. $this->newWithParenthesesFixer->getName(),
  89192. ];
  89193. }
  89194. protected function configurePreNormalisation(array $configuration): void
  89195. {
  89196. $this->newWithParenthesesFixer->configure($configuration);
  89197. }
  89198. protected function createProxyFixers(): array
  89199. {
  89200. return [
  89201. $this->newWithParenthesesFixer,
  89202. ];
  89203. }
  89204. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  89205. {
  89206. return $this->newWithParenthesesFixer->createConfigurationDefinition();
  89207. }
  89208. }
  89209. <?php
  89210. declare(strict_types=1);
  89211. namespace PhpCsFixer\Fixer\Operator;
  89212. use PhpCsFixer\Fixer\AbstractShortOperatorFixer;
  89213. use PhpCsFixer\FixerDefinition\CodeSample;
  89214. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89215. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89216. use PhpCsFixer\Tokenizer\Token;
  89217. use PhpCsFixer\Tokenizer\Tokens;
  89218. final class AssignNullCoalescingToCoalesceEqualFixer extends AbstractShortOperatorFixer
  89219. {
  89220. public function getDefinition(): FixerDefinitionInterface
  89221. {
  89222. return new FixerDefinition(
  89223. 'Use the null coalescing assignment operator `??=` where possible.',
  89224. [
  89225. new CodeSample(
  89226. "<?php\n\$foo = \$foo ?? 1;\n",
  89227. ),
  89228. ]
  89229. );
  89230. }
  89231. public function getPriority(): int
  89232. {
  89233. return -1;
  89234. }
  89235. public function isCandidate(Tokens $tokens): bool
  89236. {
  89237. return $tokens->isTokenKindFound(T_COALESCE);
  89238. }
  89239. protected function isOperatorTokenCandidate(Tokens $tokens, int $index): bool
  89240. {
  89241. if (!$tokens[$index]->isGivenKind(T_COALESCE)) {
  89242. return false;
  89243. }
  89244. $nextIndex = $tokens->getNextTokenOfKind($index, ['?', ';', [T_CLOSE_TAG]]);
  89245. return !$tokens[$nextIndex]->equals('?');
  89246. }
  89247. protected function getReplacementToken(Token $token): Token
  89248. {
  89249. return new Token([T_COALESCE_EQUAL, '??=']);
  89250. }
  89251. }
  89252. <?php
  89253. declare(strict_types=1);
  89254. namespace PhpCsFixer\Fixer\Operator;
  89255. use PhpCsFixer\AbstractFixer;
  89256. use PhpCsFixer\FixerDefinition\CodeSample;
  89257. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89258. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89259. use PhpCsFixer\Tokenizer\Token;
  89260. use PhpCsFixer\Tokenizer\Tokens;
  89261. final class ObjectOperatorWithoutWhitespaceFixer extends AbstractFixer
  89262. {
  89263. public function getDefinition(): FixerDefinitionInterface
  89264. {
  89265. return new FixerDefinition(
  89266. 'There should not be space before or after object operators `->` and `?->`.',
  89267. [new CodeSample("<?php \$a -> b;\n")]
  89268. );
  89269. }
  89270. public function isCandidate(Tokens $tokens): bool
  89271. {
  89272. return $tokens->isAnyTokenKindsFound(Token::getObjectOperatorKinds());
  89273. }
  89274. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89275. {
  89276. foreach ($tokens as $index => $token) {
  89277. if (!$token->isObjectOperator()) {
  89278. continue;
  89279. }
  89280. if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
  89281. $tokens->clearAt($index - 1);
  89282. }
  89283. if ($tokens[$index + 1]->isWhitespace(" \t") && !$tokens[$index + 2]->isComment()) {
  89284. $tokens->clearAt($index + 1);
  89285. }
  89286. }
  89287. }
  89288. }
  89289. <?php
  89290. declare(strict_types=1);
  89291. namespace PhpCsFixer\Fixer\Operator;
  89292. use PhpCsFixer\AbstractFixer;
  89293. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89294. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89295. use PhpCsFixer\FixerDefinition\VersionSpecification;
  89296. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
  89297. use PhpCsFixer\Tokenizer\Token;
  89298. use PhpCsFixer\Tokenizer\Tokens;
  89299. final class NoUselessNullsafeOperatorFixer extends AbstractFixer
  89300. {
  89301. public function getDefinition(): FixerDefinitionInterface
  89302. {
  89303. return new FixerDefinition(
  89304. 'There should not be useless Null-safe operator `?->` used.',
  89305. [
  89306. new VersionSpecificCodeSample(
  89307. '<?php
  89308. class Foo extends Bar
  89309. {
  89310. public function test() {
  89311. echo $this?->parentMethod();
  89312. }
  89313. }
  89314. ',
  89315. new VersionSpecification(8_00_00)
  89316. ),
  89317. ]
  89318. );
  89319. }
  89320. public function isCandidate(Tokens $tokens): bool
  89321. {
  89322. return \PHP_VERSION_ID >= 8_00_00 && $tokens->isAllTokenKindsFound([T_VARIABLE, T_NULLSAFE_OBJECT_OPERATOR]);
  89323. }
  89324. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89325. {
  89326. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  89327. if (!$tokens[$index]->isGivenKind(T_NULLSAFE_OBJECT_OPERATOR)) {
  89328. continue;
  89329. }
  89330. $nullsafeObjectOperatorIndex = $index;
  89331. $index = $tokens->getPrevMeaningfulToken($index);
  89332. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  89333. continue;
  89334. }
  89335. if ('$this' !== strtolower($tokens[$index]->getContent())) {
  89336. continue;
  89337. }
  89338. $tokens[$nullsafeObjectOperatorIndex] = new Token([T_OBJECT_OPERATOR, '->']);
  89339. }
  89340. }
  89341. }
  89342. <?php
  89343. declare(strict_types=1);
  89344. namespace PhpCsFixer\Fixer\Operator;
  89345. use PhpCsFixer\AbstractFixer;
  89346. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  89347. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  89348. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  89349. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  89350. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  89351. use PhpCsFixer\FixerDefinition\CodeSample;
  89352. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89353. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89354. use PhpCsFixer\Preg;
  89355. use PhpCsFixer\Tokenizer\Token;
  89356. use PhpCsFixer\Tokenizer\Tokens;
  89357. /**
  89358. @phpstan-type
  89359. @phpstan-type
  89360. @phpstan-type
  89361. @implements
  89362. */
  89363. final class NoUselessConcatOperatorFixer extends AbstractFixer implements ConfigurableFixerInterface
  89364. {
  89365. /**
  89366. @use */
  89367. use ConfigurableFixerTrait;
  89368. private const STR_DOUBLE_QUOTE = 0;
  89369. private const STR_DOUBLE_QUOTE_VAR = 1;
  89370. private const STR_SINGLE_QUOTE = 2;
  89371. public function getDefinition(): FixerDefinitionInterface
  89372. {
  89373. return new FixerDefinition(
  89374. 'There should not be useless concat operations.',
  89375. [
  89376. new CodeSample("<?php\n\$a = 'a'.'b';\n"),
  89377. new CodeSample("<?php\n\$a = 'a'.\"b\";\n", ['juggle_simple_strings' => true]),
  89378. ],
  89379. );
  89380. }
  89381. public function getPriority(): int
  89382. {
  89383. return 5;
  89384. }
  89385. public function isCandidate(Tokens $tokens): bool
  89386. {
  89387. return $tokens->isTokenKindFound('.') && $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, '"']);
  89388. }
  89389. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89390. {
  89391. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  89392. if (!$tokens[$index]->equals('.')) {
  89393. continue;
  89394. }
  89395. $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index);
  89396. if ($this->containsLinebreak($tokens, $index, $nextMeaningfulTokenIndex)) {
  89397. continue;
  89398. }
  89399. $secondOperand = $this->getConcatOperandType($tokens, $nextMeaningfulTokenIndex, 1);
  89400. if (null === $secondOperand) {
  89401. continue;
  89402. }
  89403. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($index);
  89404. if ($this->containsLinebreak($tokens, $prevMeaningfulTokenIndex, $index)) {
  89405. continue;
  89406. }
  89407. $firstOperand = $this->getConcatOperandType($tokens, $prevMeaningfulTokenIndex, -1);
  89408. if (null === $firstOperand) {
  89409. continue;
  89410. }
  89411. $this->fixConcatOperation($tokens, $firstOperand, $index, $secondOperand);
  89412. }
  89413. }
  89414. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  89415. {
  89416. return new FixerConfigurationResolver([
  89417. (new FixerOptionBuilder('juggle_simple_strings', 'Allow for simple string quote juggling if it results in more concat-operations merges.'))
  89418. ->setAllowedTypes(['bool'])
  89419. ->setDefault(false)
  89420. ->getOption(),
  89421. ]);
  89422. }
  89423. private function fixConcatOperation(Tokens $tokens, array $firstOperand, int $concatIndex, array $secondOperand): void
  89424. {
  89425. if (
  89426. (self::STR_DOUBLE_QUOTE === $firstOperand['type'] && self::STR_DOUBLE_QUOTE === $secondOperand['type'])
  89427. || (self::STR_SINGLE_QUOTE === $firstOperand['type'] && self::STR_SINGLE_QUOTE === $secondOperand['type'])
  89428. ) {
  89429. $this->mergeConstantEscapedStringOperands($tokens, $firstOperand, $concatIndex, $secondOperand);
  89430. return;
  89431. }
  89432. if (self::STR_DOUBLE_QUOTE_VAR === $firstOperand['type'] && self::STR_DOUBLE_QUOTE_VAR === $secondOperand['type']) {
  89433. if ($this->operandsCanNotBeMerged($tokens, $firstOperand, $secondOperand)) {
  89434. return;
  89435. }
  89436. $this->mergeConstantEscapedStringVarOperands($tokens, $firstOperand, $concatIndex, $secondOperand);
  89437. return;
  89438. }
  89439. $operands = [
  89440. [$firstOperand, $secondOperand],
  89441. [$secondOperand, $firstOperand],
  89442. ];
  89443. foreach ($operands as $operandPair) {
  89444. [$operand1, $operand2] = $operandPair;
  89445. if (self::STR_DOUBLE_QUOTE_VAR === $operand1['type'] && self::STR_DOUBLE_QUOTE === $operand2['type']) {
  89446. if ($this->operandsCanNotBeMerged($tokens, $operand1, $operand2)) {
  89447. return;
  89448. }
  89449. $this->mergeConstantEscapedStringVarOperands($tokens, $firstOperand, $concatIndex, $secondOperand);
  89450. return;
  89451. }
  89452. if (false === $this->configuration['juggle_simple_strings']) {
  89453. continue;
  89454. }
  89455. if (self::STR_DOUBLE_QUOTE === $operand1['type'] && self::STR_SINGLE_QUOTE === $operand2['type']) {
  89456. $operantContent = $tokens[$operand2['start']]->getContent();
  89457. if ($this->isSimpleQuotedStringContent($operantContent)) {
  89458. $this->mergeConstantEscapedStringOperands($tokens, $firstOperand, $concatIndex, $secondOperand);
  89459. }
  89460. return;
  89461. }
  89462. if (self::STR_DOUBLE_QUOTE_VAR === $operand1['type'] && self::STR_SINGLE_QUOTE === $operand2['type']) {
  89463. $operantContent = $tokens[$operand2['start']]->getContent();
  89464. if ($this->isSimpleQuotedStringContent($operantContent)) {
  89465. if ($this->operandsCanNotBeMerged($tokens, $operand1, $operand2)) {
  89466. return;
  89467. }
  89468. $this->mergeConstantEscapedStringVarOperands($tokens, $firstOperand, $concatIndex, $secondOperand);
  89469. }
  89470. return;
  89471. }
  89472. }
  89473. }
  89474. private function getConcatOperandType(Tokens $tokens, int $index, int $direction): ?array
  89475. {
  89476. if ($tokens[$index]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  89477. $firstChar = $tokens[$index]->getContent();
  89478. if ('b' === $firstChar[0] || 'B' === $firstChar[0]) {
  89479. return null;
  89480. }
  89481. return [
  89482. 'start' => $index,
  89483. 'end' => $index,
  89484. 'type' => '"' === $firstChar[0] ? self::STR_DOUBLE_QUOTE : self::STR_SINGLE_QUOTE,
  89485. ];
  89486. }
  89487. if ($tokens[$index]->equals('"')) {
  89488. $end = $tokens->getTokenOfKindSibling($index, $direction, ['"']);
  89489. return [
  89490. 'start' => 1 === $direction ? $index : $end,
  89491. 'end' => 1 === $direction ? $end : $index,
  89492. 'type' => self::STR_DOUBLE_QUOTE_VAR,
  89493. ];
  89494. }
  89495. return null;
  89496. }
  89497. private function mergeConstantEscapedStringOperands(
  89498. Tokens $tokens,
  89499. array $firstOperand,
  89500. int $concatOperatorIndex,
  89501. array $secondOperand
  89502. ): void {
  89503. $quote = self::STR_DOUBLE_QUOTE === $firstOperand['type'] || self::STR_DOUBLE_QUOTE === $secondOperand['type'] ? '"' : "'";
  89504. $firstOperandTokenContent = $tokens[$firstOperand['start']]->getContent();
  89505. $secondOperandTokenContent = $tokens[$secondOperand['start']]->getContent();
  89506. $tokens[$firstOperand['start']] = new Token(
  89507. [
  89508. T_CONSTANT_ENCAPSED_STRING,
  89509. $quote.substr($firstOperandTokenContent, 1, -1).substr($secondOperandTokenContent, 1, -1).$quote,
  89510. ],
  89511. );
  89512. $this->clearConcatAndAround($tokens, $concatOperatorIndex);
  89513. $tokens->clearTokenAndMergeSurroundingWhitespace($secondOperand['start']);
  89514. }
  89515. private function mergeConstantEscapedStringVarOperands(
  89516. Tokens $tokens,
  89517. array $firstOperand,
  89518. int $concatOperatorIndex,
  89519. array $secondOperand
  89520. ): void {
  89521. $newContent = '';
  89522. foreach ([$firstOperand, $secondOperand] as $operant) {
  89523. $operandContent = '';
  89524. for ($i = $operant['start']; $i <= $operant['end'];) {
  89525. $operandContent .= $tokens[$i]->getContent();
  89526. $i = $tokens->getNextMeaningfulToken($i);
  89527. }
  89528. $newContent .= substr($operandContent, 1, -1);
  89529. }
  89530. for ($i = $secondOperand['end']; $i >= $secondOperand['start'];) {
  89531. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  89532. $i = $tokens->getPrevMeaningfulToken($i);
  89533. }
  89534. $this->clearConcatAndAround($tokens, $concatOperatorIndex);
  89535. for ($i = $firstOperand['end']; $i > $firstOperand['start'];) {
  89536. $tokens->clearTokenAndMergeSurroundingWhitespace($i);
  89537. $i = $tokens->getPrevMeaningfulToken($i);
  89538. }
  89539. $newTokens = Tokens::fromCode('<?php "'.$newContent.'";');
  89540. $newTokensCount = \count($newTokens);
  89541. $insertTokens = [];
  89542. for ($i = 1; $i < $newTokensCount - 1; ++$i) {
  89543. $insertTokens[] = $newTokens[$i];
  89544. }
  89545. $tokens->overrideRange($firstOperand['start'], $firstOperand['start'], $insertTokens);
  89546. }
  89547. private function clearConcatAndAround(Tokens $tokens, int $concatOperatorIndex): void
  89548. {
  89549. if ($tokens[$concatOperatorIndex + 1]->isWhitespace()) {
  89550. $tokens->clearTokenAndMergeSurroundingWhitespace($concatOperatorIndex + 1);
  89551. }
  89552. $tokens->clearTokenAndMergeSurroundingWhitespace($concatOperatorIndex);
  89553. if ($tokens[$concatOperatorIndex - 1]->isWhitespace()) {
  89554. $tokens->clearTokenAndMergeSurroundingWhitespace($concatOperatorIndex - 1);
  89555. }
  89556. }
  89557. private function isSimpleQuotedStringContent(string $candidate): bool
  89558. {
  89559. return !Preg::match('#[\$"\'\\\]#', substr($candidate, 1, -1));
  89560. }
  89561. private function containsLinebreak(Tokens $tokens, int $startIndex, int $endIndex): bool
  89562. {
  89563. for ($i = $endIndex; $i > $startIndex; --$i) {
  89564. if (Preg::match('/\R/', $tokens[$i]->getContent())) {
  89565. return true;
  89566. }
  89567. }
  89568. return false;
  89569. }
  89570. private function operandsCanNotBeMerged(Tokens $tokens, array $firstOperand, array $secondOperand): bool
  89571. {
  89572. if (self::STR_DOUBLE_QUOTE_VAR !== $firstOperand['type']) {
  89573. return false;
  89574. }
  89575. if (!$tokens[$firstOperand['end'] - 1]->isGivenKind(T_VARIABLE)) {
  89576. return false;
  89577. }
  89578. $allowedPatternsForSecondOperand = [
  89579. '/^ .*/',
  89580. '/^-(?!\>)/',
  89581. ];
  89582. foreach ($allowedPatternsForSecondOperand as $allowedPattern) {
  89583. $secondOperandInnerContent = substr($tokens->generatePartialCode($secondOperand['start'], $secondOperand['end']), 1, -1);
  89584. if (Preg::match($allowedPattern, $secondOperandInnerContent)) {
  89585. return false;
  89586. }
  89587. }
  89588. return true;
  89589. }
  89590. }
  89591. <?php
  89592. declare(strict_types=1);
  89593. namespace PhpCsFixer\Fixer\Operator;
  89594. use PhpCsFixer\Fixer\AbstractIncrementOperatorFixer;
  89595. use PhpCsFixer\FixerDefinition\CodeSample;
  89596. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89597. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89598. use PhpCsFixer\Tokenizer\CT;
  89599. use PhpCsFixer\Tokenizer\Token;
  89600. use PhpCsFixer\Tokenizer\Tokens;
  89601. final class StandardizeIncrementFixer extends AbstractIncrementOperatorFixer
  89602. {
  89603. private const EXPRESSION_END_TOKENS = [
  89604. ';',
  89605. ')',
  89606. ']',
  89607. ',',
  89608. ':',
  89609. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  89610. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  89611. [T_CLOSE_TAG],
  89612. ];
  89613. public function getDefinition(): FixerDefinitionInterface
  89614. {
  89615. return new FixerDefinition(
  89616. 'Increment and decrement operators should be used if possible.',
  89617. [
  89618. new CodeSample("<?php\n\$i += 1;\n"),
  89619. new CodeSample("<?php\n\$i -= 1;\n"),
  89620. ]
  89621. );
  89622. }
  89623. public function getPriority(): int
  89624. {
  89625. return 16;
  89626. }
  89627. public function isCandidate(Tokens $tokens): bool
  89628. {
  89629. return $tokens->isAnyTokenKindsFound([T_PLUS_EQUAL, T_MINUS_EQUAL]);
  89630. }
  89631. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89632. {
  89633. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  89634. $expressionEnd = $tokens[$index];
  89635. if (!$expressionEnd->equalsAny(self::EXPRESSION_END_TOKENS)) {
  89636. continue;
  89637. }
  89638. $numberIndex = $tokens->getPrevMeaningfulToken($index);
  89639. $number = $tokens[$numberIndex];
  89640. if (!$number->isGivenKind(T_LNUMBER) || '1' !== $number->getContent()) {
  89641. continue;
  89642. }
  89643. $operatorIndex = $tokens->getPrevMeaningfulToken($numberIndex);
  89644. $operator = $tokens[$operatorIndex];
  89645. if (!$operator->isGivenKind([T_PLUS_EQUAL, T_MINUS_EQUAL])) {
  89646. continue;
  89647. }
  89648. $startIndex = $this->findStart($tokens, $operatorIndex);
  89649. $this->clearRangeLeaveComments(
  89650. $tokens,
  89651. $tokens->getPrevMeaningfulToken($operatorIndex) + 1,
  89652. $numberIndex
  89653. );
  89654. $tokens->insertAt(
  89655. $startIndex,
  89656. new Token($operator->isGivenKind(T_PLUS_EQUAL) ? [T_INC, '++'] : [T_DEC, '--'])
  89657. );
  89658. }
  89659. }
  89660. private function clearRangeLeaveComments(Tokens $tokens, int $indexStart, int $indexEnd): void
  89661. {
  89662. for ($i = $indexStart; $i <= $indexEnd; ++$i) {
  89663. $token = $tokens[$i];
  89664. if ($token->isComment()) {
  89665. continue;
  89666. }
  89667. if ($token->isWhitespace("\n\r")) {
  89668. continue;
  89669. }
  89670. $tokens->clearAt($i);
  89671. }
  89672. }
  89673. }
  89674. <?php
  89675. declare(strict_types=1);
  89676. namespace PhpCsFixer\Fixer\Operator;
  89677. use PhpCsFixer\AbstractFixer;
  89678. use PhpCsFixer\FixerDefinition\CodeSample;
  89679. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89680. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89681. use PhpCsFixer\Tokenizer\Token;
  89682. use PhpCsFixer\Tokenizer\Tokens;
  89683. final class StandardizeNotEqualsFixer extends AbstractFixer
  89684. {
  89685. public function getDefinition(): FixerDefinitionInterface
  89686. {
  89687. return new FixerDefinition(
  89688. 'Replace all `<>` with `!=`.',
  89689. [new CodeSample("<?php\n\$a = \$b <> \$c;\n")]
  89690. );
  89691. }
  89692. public function getPriority(): int
  89693. {
  89694. return 0;
  89695. }
  89696. public function isCandidate(Tokens $tokens): bool
  89697. {
  89698. return $tokens->isTokenKindFound(T_IS_NOT_EQUAL);
  89699. }
  89700. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89701. {
  89702. foreach ($tokens as $index => $token) {
  89703. if ($token->isGivenKind(T_IS_NOT_EQUAL)) {
  89704. $tokens[$index] = new Token([T_IS_NOT_EQUAL, '!=']);
  89705. }
  89706. }
  89707. }
  89708. }
  89709. <?php
  89710. declare(strict_types=1);
  89711. namespace PhpCsFixer\Fixer\Operator;
  89712. use PhpCsFixer\AbstractFixer;
  89713. use PhpCsFixer\FixerDefinition\CodeSample;
  89714. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89715. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89716. use PhpCsFixer\Tokenizer\Token;
  89717. use PhpCsFixer\Tokenizer\Tokens;
  89718. final class NotOperatorWithSpaceFixer extends AbstractFixer
  89719. {
  89720. public function getDefinition(): FixerDefinitionInterface
  89721. {
  89722. return new FixerDefinition(
  89723. 'Logical NOT operators (`!`) should have leading and trailing whitespaces.',
  89724. [new CodeSample(
  89725. '<?php
  89726. if (!$bar) {
  89727. echo "Help!";
  89728. }
  89729. '
  89730. )]
  89731. );
  89732. }
  89733. public function getPriority(): int
  89734. {
  89735. return -10;
  89736. }
  89737. public function isCandidate(Tokens $tokens): bool
  89738. {
  89739. return $tokens->isTokenKindFound('!');
  89740. }
  89741. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89742. {
  89743. for ($index = $tokens->count() - 1; $index >= 0; --$index) {
  89744. $token = $tokens[$index];
  89745. if ($token->equals('!')) {
  89746. if (!$tokens[$index + 1]->isWhitespace()) {
  89747. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
  89748. }
  89749. if (!$tokens[$index - 1]->isWhitespace()) {
  89750. $tokens->insertAt($index, new Token([T_WHITESPACE, ' ']));
  89751. }
  89752. }
  89753. }
  89754. }
  89755. }
  89756. <?php
  89757. declare(strict_types=1);
  89758. namespace PhpCsFixer\Fixer\Operator;
  89759. use PhpCsFixer\AbstractFixer;
  89760. use PhpCsFixer\FixerDefinition\CodeSample;
  89761. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89762. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89763. use PhpCsFixer\Tokenizer\Tokens;
  89764. final class NoSpaceAroundDoubleColonFixer extends AbstractFixer
  89765. {
  89766. public function getDefinition(): FixerDefinitionInterface
  89767. {
  89768. return new FixerDefinition(
  89769. 'There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).',
  89770. [new CodeSample("<?php\n\necho Foo\\Bar :: class;\n")]
  89771. );
  89772. }
  89773. public function getPriority(): int
  89774. {
  89775. return 1;
  89776. }
  89777. public function isCandidate(Tokens $tokens): bool
  89778. {
  89779. return $tokens->isTokenKindFound(T_DOUBLE_COLON);
  89780. }
  89781. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89782. {
  89783. for ($index = \count($tokens) - 2; $index > 1; --$index) {
  89784. if ($tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
  89785. $this->removeSpace($tokens, $index, 1);
  89786. $this->removeSpace($tokens, $index, -1);
  89787. }
  89788. }
  89789. }
  89790. private function removeSpace(Tokens $tokens, int $index, int $direction): void
  89791. {
  89792. if (!$tokens[$index + $direction]->isWhitespace()) {
  89793. return;
  89794. }
  89795. if ($tokens[$tokens->getNonWhitespaceSibling($index, $direction)]->isComment()) {
  89796. return;
  89797. }
  89798. $tokens->clearAt($index + $direction);
  89799. }
  89800. }
  89801. <?php
  89802. declare(strict_types=1);
  89803. namespace PhpCsFixer\Fixer\ConstantNotation;
  89804. use PhpCsFixer\AbstractFixer;
  89805. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  89806. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  89807. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  89808. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  89809. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  89810. use PhpCsFixer\FixerDefinition\CodeSample;
  89811. use PhpCsFixer\FixerDefinition\FixerDefinition;
  89812. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  89813. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  89814. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  89815. use PhpCsFixer\Tokenizer\Token;
  89816. use PhpCsFixer\Tokenizer\Tokens;
  89817. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  89818. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  89819. /**
  89820. @phpstan-type
  89821. @phpstan-type
  89822. @implements
  89823. */
  89824. final class NativeConstantInvocationFixer extends AbstractFixer implements ConfigurableFixerInterface
  89825. {
  89826. /**
  89827. @use */
  89828. use ConfigurableFixerTrait;
  89829. private array $constantsToEscape = [];
  89830. private array $caseInsensitiveConstantsToEscape = [];
  89831. public function getDefinition(): FixerDefinitionInterface
  89832. {
  89833. return new FixerDefinition(
  89834. 'Add leading `\` before constant invocation of internal constant to speed up resolving. Constant name match is case-sensitive, except for `null`, `false` and `true`.',
  89835. [
  89836. new CodeSample("<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n"),
  89837. new CodeSample(
  89838. '<?php
  89839. namespace space1 {
  89840. echo PHP_VERSION;
  89841. }
  89842. namespace {
  89843. echo M_PI;
  89844. }
  89845. ',
  89846. ['scope' => 'namespaced']
  89847. ),
  89848. new CodeSample(
  89849. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  89850. [
  89851. 'include' => [
  89852. 'MY_CUSTOM_PI',
  89853. ],
  89854. ]
  89855. ),
  89856. new CodeSample(
  89857. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  89858. [
  89859. 'fix_built_in' => false,
  89860. 'include' => [
  89861. 'MY_CUSTOM_PI',
  89862. ],
  89863. ]
  89864. ),
  89865. new CodeSample(
  89866. "<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);\n",
  89867. [
  89868. 'exclude' => [
  89869. 'M_PI',
  89870. ],
  89871. ]
  89872. ),
  89873. ],
  89874. null,
  89875. 'Risky when any of the constants are namespaced or overridden.'
  89876. );
  89877. }
  89878. public function getPriority(): int
  89879. {
  89880. return 1;
  89881. }
  89882. public function isCandidate(Tokens $tokens): bool
  89883. {
  89884. return $tokens->isTokenKindFound(T_STRING);
  89885. }
  89886. public function isRisky(): bool
  89887. {
  89888. return true;
  89889. }
  89890. protected function configurePostNormalisation(): void
  89891. {
  89892. $uniqueConfiguredExclude = array_unique($this->configuration['exclude']);
  89893. $constantsToEscape = array_values($this->configuration['include']);
  89894. if (true === $this->configuration['fix_built_in']) {
  89895. $getDefinedConstants = get_defined_constants(true);
  89896. unset($getDefinedConstants['user']);
  89897. foreach ($getDefinedConstants as $constants) {
  89898. $constantsToEscape = [...$constantsToEscape, ...array_keys($constants)];
  89899. }
  89900. }
  89901. $constantsToEscape = array_diff(
  89902. array_unique($constantsToEscape),
  89903. $uniqueConfiguredExclude
  89904. );
  89905. static $caseInsensitiveConstants = ['null', 'false', 'true'];
  89906. $caseInsensitiveConstantsToEscape = [];
  89907. foreach ($constantsToEscape as $constantIndex => $constant) {
  89908. $loweredConstant = strtolower($constant);
  89909. if (\in_array($loweredConstant, $caseInsensitiveConstants, true)) {
  89910. $caseInsensitiveConstantsToEscape[] = $loweredConstant;
  89911. unset($constantsToEscape[$constantIndex]);
  89912. }
  89913. }
  89914. $caseInsensitiveConstantsToEscape = array_diff(
  89915. array_unique($caseInsensitiveConstantsToEscape),
  89916. array_map(
  89917. static fn (string $function): string => strtolower($function),
  89918. $uniqueConfiguredExclude,
  89919. ),
  89920. );
  89921. $this->constantsToEscape = array_fill_keys($constantsToEscape, true);
  89922. ksort($this->constantsToEscape);
  89923. $this->caseInsensitiveConstantsToEscape = array_fill_keys($caseInsensitiveConstantsToEscape, true);
  89924. ksort($this->caseInsensitiveConstantsToEscape);
  89925. }
  89926. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  89927. {
  89928. if ('all' === $this->configuration['scope']) {
  89929. $this->fixConstantInvocations($tokens, 0, \count($tokens) - 1);
  89930. return;
  89931. }
  89932. $namespaces = $tokens->getNamespaceDeclarations();
  89933. foreach (array_reverse($namespaces) as $namespace) {
  89934. if ($namespace->isGlobalNamespace()) {
  89935. continue;
  89936. }
  89937. $this->fixConstantInvocations($tokens, $namespace->getScopeStartIndex(), $namespace->getScopeEndIndex());
  89938. }
  89939. }
  89940. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  89941. {
  89942. $constantChecker = static function (array $value): bool {
  89943. foreach ($value as $constantName) {
  89944. if (trim($constantName) !== $constantName) {
  89945. throw new InvalidOptionsException(\sprintf(
  89946. 'Each element must be a non-empty, trimmed string, got "%s" instead.',
  89947. get_debug_type($constantName)
  89948. ));
  89949. }
  89950. }
  89951. return true;
  89952. };
  89953. return new FixerConfigurationResolver([
  89954. (new FixerOptionBuilder('fix_built_in', 'Whether to fix constants returned by `get_defined_constants`. User constants are not accounted in this list and must be specified in the include one.'))
  89955. ->setAllowedTypes(['bool'])
  89956. ->setDefault(true)
  89957. ->getOption(),
  89958. (new FixerOptionBuilder('include', 'List of additional constants to fix.'))
  89959. ->setAllowedTypes(['string[]'])
  89960. ->setAllowedValues([$constantChecker])
  89961. ->setDefault([])
  89962. ->getOption(),
  89963. (new FixerOptionBuilder('exclude', 'List of constants to ignore.'))
  89964. ->setAllowedTypes(['string[]'])
  89965. ->setAllowedValues([$constantChecker])
  89966. ->setDefault(['null', 'false', 'true'])
  89967. ->getOption(),
  89968. (new FixerOptionBuilder('scope', 'Only fix constant invocations that are made within a namespace or fix all.'))
  89969. ->setAllowedValues(['all', 'namespaced'])
  89970. ->setDefault('all')
  89971. ->getOption(),
  89972. (new FixerOptionBuilder('strict', 'Whether leading `\` of constant invocation not meant to have it should be removed.'))
  89973. ->setAllowedTypes(['bool'])
  89974. ->setDefault(true)
  89975. ->getOption(),
  89976. ]);
  89977. }
  89978. private function fixConstantInvocations(Tokens $tokens, int $startIndex, int $endIndex): void
  89979. {
  89980. $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
  89981. $useConstantDeclarations = [];
  89982. foreach ($useDeclarations as $use) {
  89983. if ($use->isConstant()) {
  89984. $useConstantDeclarations[$use->getShortName()] = true;
  89985. }
  89986. }
  89987. $tokenAnalyzer = new TokensAnalyzer($tokens);
  89988. for ($index = $endIndex; $index > $startIndex; --$index) {
  89989. $token = $tokens[$index];
  89990. if (!$token->isGivenKind(T_STRING)) {
  89991. continue;
  89992. }
  89993. if (!$tokenAnalyzer->isConstantInvocation($index)) {
  89994. continue;
  89995. }
  89996. $tokenContent = $token->getContent();
  89997. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  89998. if (!isset($this->constantsToEscape[$tokenContent]) && !isset($this->caseInsensitiveConstantsToEscape[strtolower($tokenContent)])) {
  89999. if (false === $this->configuration['strict']) {
  90000. continue;
  90001. }
  90002. if (!$tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  90003. continue;
  90004. }
  90005. $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  90006. if ($tokens[$prevPrevIndex]->isGivenKind(T_STRING)) {
  90007. continue;
  90008. }
  90009. $tokens->clearTokenAndMergeSurroundingWhitespace($prevIndex);
  90010. continue;
  90011. }
  90012. if (isset($useConstantDeclarations[$tokenContent])) {
  90013. continue;
  90014. }
  90015. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  90016. continue;
  90017. }
  90018. $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
  90019. }
  90020. }
  90021. }
  90022. <?php
  90023. declare(strict_types=1);
  90024. namespace PhpCsFixer\Fixer;
  90025. interface ExperimentalFixerInterface extends FixerInterface {}
  90026. <?php
  90027. declare(strict_types=1);
  90028. namespace PhpCsFixer\ConfigurationException;
  90029. final class RequiredFixerConfigurationException extends InvalidFixerConfigurationException {}
  90030. <?php
  90031. declare(strict_types=1);
  90032. namespace PhpCsFixer\ConfigurationException;
  90033. final class InvalidForEnvFixerConfigurationException extends InvalidFixerConfigurationException {}
  90034. <?php
  90035. declare(strict_types=1);
  90036. namespace PhpCsFixer\ConfigurationException;
  90037. use PhpCsFixer\Console\Command\FixCommandExitStatusCalculator;
  90038. class InvalidConfigurationException extends \InvalidArgumentException
  90039. {
  90040. public function __construct(string $message, ?int $code = null, ?\Throwable $previous = null)
  90041. {
  90042. parent::__construct(
  90043. $message,
  90044. $code ?? FixCommandExitStatusCalculator::EXIT_STATUS_FLAG_HAS_INVALID_CONFIG,
  90045. $previous
  90046. );
  90047. }
  90048. }
  90049. <?php
  90050. declare(strict_types=1);
  90051. namespace PhpCsFixer\ConfigurationException;
  90052. use PhpCsFixer\Console\Command\FixCommandExitStatusCalculator;
  90053. class InvalidFixerConfigurationException extends InvalidConfigurationException
  90054. {
  90055. private string $fixerName;
  90056. public function __construct(string $fixerName, string $message, ?\Throwable $previous = null)
  90057. {
  90058. parent::__construct(
  90059. \sprintf('[%s] %s', $fixerName, $message),
  90060. FixCommandExitStatusCalculator::EXIT_STATUS_FLAG_HAS_INVALID_FIXER_CONFIG,
  90061. $previous
  90062. );
  90063. $this->fixerName = $fixerName;
  90064. }
  90065. public function getFixerName(): string
  90066. {
  90067. return $this->fixerName;
  90068. }
  90069. }
  90070. <?php
  90071. declare(strict_types=1);
  90072. namespace PhpCsFixer\Documentation;
  90073. use PhpCsFixer\Fixer\FixerInterface;
  90074. use PhpCsFixer\Preg;
  90075. use PhpCsFixer\Utils;
  90076. /**
  90077. @readonly
  90078. */
  90079. final class DocumentationLocator
  90080. {
  90081. private string $path;
  90082. public function __construct()
  90083. {
  90084. $this->path = \dirname(__DIR__, 2).'/doc';
  90085. }
  90086. public function getFixersDocumentationDirectoryPath(): string
  90087. {
  90088. return $this->path.'/rules';
  90089. }
  90090. public function getFixersDocumentationIndexFilePath(): string
  90091. {
  90092. return $this->getFixersDocumentationDirectoryPath().'/index.rst';
  90093. }
  90094. public function getFixerDocumentationFilePath(FixerInterface $fixer): string
  90095. {
  90096. return $this->getFixersDocumentationDirectoryPath().'/'.Preg::replaceCallback(
  90097. '/^.*\\\(.+)\\\(.+)Fixer$/',
  90098. static fn (array $matches): string => Utils::camelCaseToUnderscore($matches[1]).'/'.Utils::camelCaseToUnderscore($matches[2]),
  90099. \get_class($fixer)
  90100. ).'.rst';
  90101. }
  90102. public function getFixerDocumentationFileRelativePath(FixerInterface $fixer): string
  90103. {
  90104. return Preg::replace(
  90105. '#^'.preg_quote($this->getFixersDocumentationDirectoryPath(), '#').'/#',
  90106. '',
  90107. $this->getFixerDocumentationFilePath($fixer)
  90108. );
  90109. }
  90110. public function getRuleSetsDocumentationDirectoryPath(): string
  90111. {
  90112. return $this->path.'/ruleSets';
  90113. }
  90114. public function getRuleSetsDocumentationIndexFilePath(): string
  90115. {
  90116. return $this->getRuleSetsDocumentationDirectoryPath().'/index.rst';
  90117. }
  90118. public function getRuleSetsDocumentationFilePath(string $name): string
  90119. {
  90120. return $this->getRuleSetsDocumentationDirectoryPath().'/'.str_replace(':risky', 'Risky', ucfirst(substr($name, 1))).'.rst';
  90121. }
  90122. public function getUsageFilePath(): string
  90123. {
  90124. return $this->path.'/usage.rst';
  90125. }
  90126. }
  90127. <?php
  90128. declare(strict_types=1);
  90129. namespace PhpCsFixer\Documentation;
  90130. use PhpCsFixer\Fixer\FixerInterface;
  90131. use PhpCsFixer\Preg;
  90132. use PhpCsFixer\RuleSet\DeprecatedRuleSetDescriptionInterface;
  90133. use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
  90134. use PhpCsFixer\Utils;
  90135. /**
  90136. @readonly
  90137. */
  90138. final class RuleSetDocumentationGenerator
  90139. {
  90140. private DocumentationLocator $locator;
  90141. public function __construct(DocumentationLocator $locator)
  90142. {
  90143. $this->locator = $locator;
  90144. }
  90145. public function generateRuleSetsDocumentation(RuleSetDescriptionInterface $definition, array $fixers): string
  90146. {
  90147. $fixerNames = [];
  90148. foreach ($fixers as $fixer) {
  90149. $fixerNames[$fixer->getName()] = $fixer;
  90150. }
  90151. $title = "Rule set ``{$definition->getName()}``";
  90152. $titleLine = str_repeat('=', \strlen($title));
  90153. $doc = "{$titleLine}\n{$title}\n{$titleLine}\n\n".$definition->getDescription();
  90154. $warnings = [];
  90155. if ($definition instanceof DeprecatedRuleSetDescriptionInterface) {
  90156. $deprecationDescription = <<<'RST'
  90157. This rule set is deprecated and will be removed in the next major version
  90158. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  90159. RST;
  90160. $alternatives = $definition->getSuccessorsNames();
  90161. if (0 !== \count($alternatives)) {
  90162. $deprecationDescription .= RstUtils::toRst(
  90163. \sprintf(
  90164. "\n\nYou should use %s instead.",
  90165. Utils::naturalLanguageJoinWithBackticks($alternatives)
  90166. ),
  90167. 0
  90168. );
  90169. } else {
  90170. $deprecationDescription .= 'No replacement available.';
  90171. }
  90172. $warnings[] = $deprecationDescription;
  90173. }
  90174. if ($definition->isRisky()) {
  90175. $warnings[] = <<<'RST'
  90176. This set contains rules that are risky
  90177. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  90178. Using this rule set may lead to changes in your code's logic and behaviour. Use it with caution and review changes before incorporating them into your code base.
  90179. RST;
  90180. }
  90181. if ([] !== $warnings) {
  90182. $warningsHeader = 1 === \count($warnings) ? 'Warning' : 'Warnings';
  90183. $warningsHeaderLine = str_repeat('-', \strlen($warningsHeader));
  90184. $doc .= "\n\n".implode(
  90185. "\n",
  90186. [
  90187. $warningsHeader,
  90188. $warningsHeaderLine,
  90189. ...$warnings,
  90190. ]
  90191. );
  90192. }
  90193. $rules = $definition->getRules();
  90194. if ([] === $rules) {
  90195. $doc .= "\n\nThis is an empty set.";
  90196. } else {
  90197. $enabledRules = array_filter($rules, static fn ($config) => false !== $config);
  90198. $disabledRules = array_filter($rules, static fn ($config) => false === $config);
  90199. $listRules = function (array $rules) use (&$doc, $fixerNames): void {
  90200. foreach ($rules as $rule => $config) {
  90201. if (str_starts_with($rule, '@')) {
  90202. $ruleSetPath = $this->locator->getRuleSetsDocumentationFilePath($rule);
  90203. $ruleSetPath = substr($ruleSetPath, strrpos($ruleSetPath, '/'));
  90204. $doc .= "\n- `{$rule} <.{$ruleSetPath}>`_";
  90205. } else {
  90206. $path = Preg::replace(
  90207. '#^'.preg_quote($this->locator->getFixersDocumentationDirectoryPath(), '#').'/#',
  90208. './../rules/',
  90209. $this->locator->getFixerDocumentationFilePath($fixerNames[$rule])
  90210. );
  90211. $doc .= "\n- `{$rule} <{$path}>`_";
  90212. }
  90213. if (!\is_bool($config)) {
  90214. $doc .= " with config:\n\n ``".Utils::toString($config)."``\n";
  90215. }
  90216. }
  90217. };
  90218. if ([] !== $enabledRules) {
  90219. $doc .= "\n\nRules\n-----\n";
  90220. $listRules($enabledRules);
  90221. }
  90222. if ([] !== $disabledRules) {
  90223. $doc .= "\n\nDisabled rules\n--------------\n";
  90224. $listRules($disabledRules);
  90225. }
  90226. }
  90227. return $doc."\n";
  90228. }
  90229. public function generateRuleSetsDocumentationIndex(array $setDefinitions): string
  90230. {
  90231. $documentation = <<<'RST'
  90232. ===========================
  90233. List of Available Rule sets
  90234. ===========================
  90235. RST;
  90236. foreach ($setDefinitions as $path => $definition) {
  90237. $path = substr($path, strrpos($path, '/'));
  90238. $attributes = [];
  90239. if ($definition instanceof DeprecatedRuleSetDescriptionInterface) {
  90240. $attributes[] = 'deprecated';
  90241. }
  90242. $attributes = 0 === \count($attributes)
  90243. ? ''
  90244. : ' *('.implode(', ', $attributes).')*';
  90245. $documentation .= "\n- `{$definition->getName()} <.{$path}>`_{$attributes}";
  90246. }
  90247. return $documentation."\n";
  90248. }
  90249. }
  90250. <?php
  90251. declare(strict_types=1);
  90252. namespace PhpCsFixer\Documentation;
  90253. use PhpCsFixer\Preg;
  90254. final class RstUtils
  90255. {
  90256. private function __construct()
  90257. {
  90258. }
  90259. public static function toRst(string $string, int $indent = 0): string
  90260. {
  90261. $string = wordwrap(self::ensureProperInlineCode($string), 80 - $indent);
  90262. return 0 === $indent ? $string : self::indent($string, $indent);
  90263. }
  90264. public static function ensureProperInlineCode(string $string): string
  90265. {
  90266. return Preg::replace('/(?<!`)(`[^`]+`)(?!`)/', '`$1`', $string);
  90267. }
  90268. public static function indent(string $string, int $indent): string
  90269. {
  90270. return Preg::replace('/(\n)(?!\n|$)/', '$1'.str_repeat(' ', $indent), $string);
  90271. }
  90272. }
  90273. <?php
  90274. declare(strict_types=1);
  90275. namespace PhpCsFixer\Documentation;
  90276. use PhpCsFixer\Console\Command\HelpCommand;
  90277. use PhpCsFixer\Differ\FullDiffer;
  90278. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  90279. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  90280. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  90281. use PhpCsFixer\Fixer\FixerInterface;
  90282. use PhpCsFixer\FixerConfiguration\AliasedFixerOption;
  90283. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  90284. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOptionInterface;
  90285. use PhpCsFixer\FixerDefinition\CodeSampleInterface;
  90286. use PhpCsFixer\FixerDefinition\FileSpecificCodeSampleInterface;
  90287. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
  90288. use PhpCsFixer\Preg;
  90289. use PhpCsFixer\RuleSet\RuleSet;
  90290. use PhpCsFixer\RuleSet\RuleSets;
  90291. use PhpCsFixer\StdinFileInfo;
  90292. use PhpCsFixer\Tokenizer\Tokens;
  90293. use PhpCsFixer\Utils;
  90294. /**
  90295. @readonly
  90296. */
  90297. final class FixerDocumentGenerator
  90298. {
  90299. private DocumentationLocator $locator;
  90300. private FullDiffer $differ;
  90301. public function __construct(DocumentationLocator $locator)
  90302. {
  90303. $this->locator = $locator;
  90304. $this->differ = new FullDiffer();
  90305. }
  90306. public function generateFixerDocumentation(FixerInterface $fixer): string
  90307. {
  90308. $name = $fixer->getName();
  90309. $title = "Rule ``{$name}``";
  90310. $titleLine = str_repeat('=', \strlen($title));
  90311. $doc = "{$titleLine}\n{$title}\n{$titleLine}";
  90312. $definition = $fixer->getDefinition();
  90313. $doc .= "\n\n".RstUtils::toRst($definition->getSummary());
  90314. $description = $definition->getDescription();
  90315. if (null !== $description) {
  90316. $description = RstUtils::toRst($description);
  90317. $doc .= <<<RST
  90318. Description
  90319. -----------
  90320. {$description}
  90321. RST;
  90322. }
  90323. $deprecationDescription = '';
  90324. if ($fixer instanceof DeprecatedFixerInterface) {
  90325. $deprecationDescription = <<<'RST'
  90326. This rule is deprecated and will be removed in the next major version
  90327. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  90328. RST;
  90329. $alternatives = $fixer->getSuccessorsNames();
  90330. if (0 !== \count($alternatives)) {
  90331. $deprecationDescription .= RstUtils::toRst(\sprintf(
  90332. "\n\nYou should use %s instead.",
  90333. Utils::naturalLanguageJoinWithBackticks($alternatives)
  90334. ), 0);
  90335. }
  90336. }
  90337. $experimentalDescription = '';
  90338. if ($fixer instanceof ExperimentalFixerInterface) {
  90339. $experimentalDescriptionRaw = RstUtils::toRst('Rule is not covered with backward compatibility promise, use it at your own risk. Rule\'s behaviour may be changed at any point, including rule\'s name; its options\' names, availability and allowed values; its default configuration. Rule may be even removed without prior notice. Feel free to provide feedback and help with determining final state of the rule.', 0);
  90340. $experimentalDescription = <<<RST
  90341. This rule is experimental
  90342. ~~~~~~~~~~~~~~~~~~~~~~~~~
  90343. {$experimentalDescriptionRaw}
  90344. RST;
  90345. }
  90346. $riskyDescription = '';
  90347. $riskyDescriptionRaw = $definition->getRiskyDescription();
  90348. if (null !== $riskyDescriptionRaw) {
  90349. $riskyDescriptionRaw = RstUtils::toRst($riskyDescriptionRaw, 0);
  90350. $riskyDescription = <<<RST
  90351. Using this rule is risky
  90352. ~~~~~~~~~~~~~~~~~~~~~~~~
  90353. {$riskyDescriptionRaw}
  90354. RST;
  90355. }
  90356. if ('' !== $deprecationDescription || '' !== $riskyDescription) {
  90357. $warningsHeader = 'Warning';
  90358. if ('' !== $deprecationDescription && '' !== $riskyDescription) {
  90359. $warningsHeader = 'Warnings';
  90360. }
  90361. $warningsHeaderLine = str_repeat('-', \strlen($warningsHeader));
  90362. $doc .= "\n\n".implode("\n", array_filter(
  90363. [
  90364. $warningsHeader,
  90365. $warningsHeaderLine,
  90366. $deprecationDescription,
  90367. $experimentalDescription,
  90368. $riskyDescription,
  90369. ],
  90370. static fn (string $text): bool => '' !== $text
  90371. ));
  90372. }
  90373. if ($fixer instanceof ConfigurableFixerInterface) {
  90374. $doc .= <<<'RST'
  90375. Configuration
  90376. -------------
  90377. RST;
  90378. $configurationDefinition = $fixer->getConfigurationDefinition();
  90379. foreach ($configurationDefinition->getOptions() as $option) {
  90380. $optionInfo = "``{$option->getName()}``";
  90381. $optionInfo .= "\n".str_repeat('~', \strlen($optionInfo));
  90382. if ($option instanceof DeprecatedFixerOptionInterface) {
  90383. $deprecationMessage = RstUtils::toRst($option->getDeprecationMessage());
  90384. $optionInfo .= "\n\n.. warning:: This option is deprecated and will be removed in the next major version. {$deprecationMessage}";
  90385. }
  90386. $optionInfo .= "\n\n".RstUtils::toRst($option->getDescription());
  90387. if ($option instanceof AliasedFixerOption) {
  90388. $optionInfo .= "\n\n.. note:: The previous name of this option was ``{$option->getAlias()}`` but it is now deprecated and will be removed in the next major version.";
  90389. }
  90390. $allowed = HelpCommand::getDisplayableAllowedValues($option);
  90391. if (null === $allowed) {
  90392. $allowedKind = 'Allowed types';
  90393. $allowed = array_map(
  90394. static fn (string $value): string => '``'.Utils::convertArrayTypeToList($value).'``',
  90395. $option->getAllowedTypes(),
  90396. );
  90397. } else {
  90398. $allowedKind = 'Allowed values';
  90399. $allowed = array_map(static fn ($value): string => $value instanceof AllowedValueSubset
  90400. ? 'a subset of ``'.Utils::toString($value->getAllowedValues()).'``'
  90401. : '``'.Utils::toString($value).'``', $allowed);
  90402. }
  90403. $allowed = Utils::naturalLanguageJoin($allowed, '');
  90404. $optionInfo .= "\n\n{$allowedKind}: {$allowed}";
  90405. if ($option->hasDefault()) {
  90406. $default = Utils::toString($option->getDefault());
  90407. $optionInfo .= "\n\nDefault value: ``{$default}``";
  90408. } else {
  90409. $optionInfo .= "\n\nThis option is required.";
  90410. }
  90411. $doc .= "\n\n{$optionInfo}";
  90412. }
  90413. }
  90414. $samples = $definition->getCodeSamples();
  90415. if (0 !== \count($samples)) {
  90416. $doc .= <<<'RST'
  90417. Examples
  90418. --------
  90419. RST;
  90420. foreach ($samples as $index => $sample) {
  90421. $title = \sprintf('Example #%d', $index + 1);
  90422. $titleLine = str_repeat('~', \strlen($title));
  90423. $doc .= "\n\n{$title}\n{$titleLine}";
  90424. if ($fixer instanceof ConfigurableFixerInterface) {
  90425. if (null === $sample->getConfiguration()) {
  90426. $doc .= "\n\n*Default* configuration.";
  90427. } else {
  90428. $doc .= \sprintf(
  90429. "\n\nWith configuration: ``%s``.",
  90430. Utils::toString($sample->getConfiguration())
  90431. );
  90432. }
  90433. }
  90434. $doc .= "\n".$this->generateSampleDiff($fixer, $sample, $index + 1, $name);
  90435. }
  90436. }
  90437. $ruleSetConfigs = self::getSetsOfRule($name);
  90438. if ([] !== $ruleSetConfigs) {
  90439. $plural = 1 !== \count($ruleSetConfigs) ? 's' : '';
  90440. $doc .= <<<RST
  90441. Rule sets
  90442. ---------
  90443. The rule is part of the following rule set{$plural}:\n\n
  90444. RST;
  90445. foreach ($ruleSetConfigs as $set => $config) {
  90446. $ruleSetPath = $this->locator->getRuleSetsDocumentationFilePath($set);
  90447. $ruleSetPath = substr($ruleSetPath, strrpos($ruleSetPath, '/'));
  90448. $configInfo = (null !== $config)
  90449. ? " with config:\n\n ``".Utils::toString($config)."``\n"
  90450. : '';
  90451. $doc .= <<<RST
  90452. - `{$set} <./../../ruleSets{$ruleSetPath}>`_{$configInfo}\n
  90453. RST;
  90454. }
  90455. $doc = trim($doc);
  90456. }
  90457. $reflectionObject = new \ReflectionObject($fixer);
  90458. $className = str_replace('\\', '\\\\', $reflectionObject->getName());
  90459. $fileName = $reflectionObject->getFileName();
  90460. $fileName = str_replace('\\', '/', $fileName);
  90461. $fileName = substr($fileName, strrpos($fileName, '/src/Fixer/') + 1);
  90462. $fileName = "`{$className} <./../../../{$fileName}>`_";
  90463. $testFileName = Preg::replace('~.*\K/src/(?=Fixer/)~', '/tests/', $fileName);
  90464. $testFileName = Preg::replace('~PhpCsFixer\\\\\\\\\K(?=Fixer\\\\\\\)~', 'Tests\\\\\\\\', $testFileName);
  90465. $testFileName = Preg::replace('~(?= <|\.php>)~', 'Test', $testFileName);
  90466. $doc .= <<<RST
  90467. References
  90468. ----------
  90469. - Fixer class: {$fileName}
  90470. - Test class: {$testFileName}
  90471. The test class defines officially supported behaviour. Each test case is a part of our backward compatibility promise.
  90472. RST;
  90473. $doc = str_replace("\t", '<TAB>', $doc);
  90474. return "{$doc}\n";
  90475. }
  90476. public static function getSetsOfRule(string $ruleName): array
  90477. {
  90478. $ruleSetConfigs = [];
  90479. foreach (RuleSets::getSetDefinitionNames() as $set) {
  90480. $ruleSet = new RuleSet([$set => true]);
  90481. if ($ruleSet->hasRule($ruleName)) {
  90482. $ruleSetConfigs[$set] = $ruleSet->getRuleConfiguration($ruleName);
  90483. }
  90484. }
  90485. return $ruleSetConfigs;
  90486. }
  90487. public function generateFixersDocumentationIndex(array $fixers): string
  90488. {
  90489. $overrideGroups = [
  90490. 'PhpUnit' => 'PHPUnit',
  90491. 'PhpTag' => 'PHP Tag',
  90492. 'Phpdoc' => 'PHPDoc',
  90493. ];
  90494. usort($fixers, static fn (FixerInterface $a, FixerInterface $b): int => \get_class($a) <=> \get_class($b));
  90495. $documentation = <<<'RST'
  90496. =======================
  90497. List of Available Rules
  90498. =======================
  90499. RST;
  90500. $currentGroup = null;
  90501. foreach ($fixers as $fixer) {
  90502. $namespace = Preg::replace('/^.*\\\(.+)\\\.+Fixer$/', '$1', \get_class($fixer));
  90503. $group = $overrideGroups[$namespace] ?? Preg::replace('/(?<=[[:lower:]])(?=[[:upper:]])/', ' ', $namespace);
  90504. if ($group !== $currentGroup) {
  90505. $underline = str_repeat('-', \strlen($group));
  90506. $documentation .= "\n\n{$group}\n{$underline}\n";
  90507. $currentGroup = $group;
  90508. }
  90509. $path = './'.$this->locator->getFixerDocumentationFileRelativePath($fixer);
  90510. $attributes = [];
  90511. if ($fixer instanceof DeprecatedFixerInterface) {
  90512. $attributes[] = 'deprecated';
  90513. }
  90514. if ($fixer instanceof ExperimentalFixerInterface) {
  90515. $attributes[] = 'experimental';
  90516. }
  90517. if ($fixer->isRisky()) {
  90518. $attributes[] = 'risky';
  90519. }
  90520. $attributes = 0 === \count($attributes)
  90521. ? ''
  90522. : ' *('.implode(', ', $attributes).')*';
  90523. $summary = str_replace('`', '``', $fixer->getDefinition()->getSummary());
  90524. $documentation .= <<<RST
  90525. - `{$fixer->getName()} <{$path}>`_{$attributes}
  90526. {$summary}
  90527. RST;
  90528. }
  90529. return "{$documentation}\n";
  90530. }
  90531. private function generateSampleDiff(FixerInterface $fixer, CodeSampleInterface $sample, int $sampleNumber, string $ruleName): string
  90532. {
  90533. if ($sample instanceof VersionSpecificCodeSampleInterface && !$sample->isSuitableFor(\PHP_VERSION_ID)) {
  90534. $existingFile = @file_get_contents($this->locator->getFixerDocumentationFilePath($fixer));
  90535. if (false !== $existingFile) {
  90536. Preg::match("/\\RExample #{$sampleNumber}\\R.+?(?<diff>\\R\\.\\. code-block:: diff\\R\\R.*?)\\R(?:\\R\\S|$)/s", $existingFile, $matches);
  90537. if (isset($matches['diff'])) {
  90538. return $matches['diff'];
  90539. }
  90540. }
  90541. $error = <<<RST
  90542. .. error::
  90543. Cannot generate diff for code sample #{$sampleNumber} of rule {$ruleName}:
  90544. the sample is not suitable for current version of PHP (%s).
  90545. RST;
  90546. return \sprintf($error, PHP_VERSION);
  90547. }
  90548. $old = $sample->getCode();
  90549. $tokens = Tokens::fromCode($old);
  90550. $file = $sample instanceof FileSpecificCodeSampleInterface
  90551. ? $sample->getSplFileInfo()
  90552. : new StdinFileInfo();
  90553. if ($fixer instanceof ConfigurableFixerInterface) {
  90554. $fixer->configure($sample->getConfiguration() ?? []);
  90555. }
  90556. $fixer->fix($file, $tokens);
  90557. $diff = $this->differ->diff($old, $tokens->generateCode());
  90558. $diff = Preg::replace('/@@[ \+\-\d,]+@@\n/', '', $diff);
  90559. $diff = Preg::replace('/\r/', '^M', $diff);
  90560. $diff = Preg::replace('/^ $/m', '', $diff);
  90561. $diff = Preg::replace('/\n$/', '', $diff);
  90562. $diff = RstUtils::indent($diff, 3);
  90563. return <<<RST
  90564. .. code-block:: diff
  90565. {$diff}
  90566. RST;
  90567. }
  90568. }
  90569. <?php
  90570. declare(strict_types=1);
  90571. namespace PhpCsFixer\RuleSet;
  90572. use Symfony\Component\Finder\Finder;
  90573. final class RuleSets
  90574. {
  90575. private static ?array $setDefinitions = null;
  90576. public static function getSetDefinitions(): array
  90577. {
  90578. if (null === self::$setDefinitions) {
  90579. self::$setDefinitions = [];
  90580. foreach (Finder::create()->files()->in(__DIR__.'/Sets') as $file) {
  90581. $class = 'PhpCsFixer\RuleSet\Sets\\'.$file->getBasename('.php');
  90582. $set = new $class();
  90583. self::$setDefinitions[$set->getName()] = $set;
  90584. }
  90585. uksort(self::$setDefinitions, static fn (string $x, string $y): int => strnatcmp($x, $y));
  90586. }
  90587. return self::$setDefinitions;
  90588. }
  90589. public static function getSetDefinitionNames(): array
  90590. {
  90591. return array_keys(self::getSetDefinitions());
  90592. }
  90593. public static function getSetDefinition(string $name): RuleSetDescriptionInterface
  90594. {
  90595. $definitions = self::getSetDefinitions();
  90596. if (!isset($definitions[$name])) {
  90597. throw new \InvalidArgumentException(\sprintf('Set "%s" does not exist.', $name));
  90598. }
  90599. return $definitions[$name];
  90600. }
  90601. }
  90602. <?php
  90603. declare(strict_types=1);
  90604. namespace PhpCsFixer\RuleSet;
  90605. interface RuleSetInterface
  90606. {
  90607. public function __construct(array $set = []);
  90608. public function getRuleConfiguration(string $rule): ?array;
  90609. public function getRules(): array;
  90610. public function hasRule(string $rule): bool;
  90611. }
  90612. <?php
  90613. declare(strict_types=1);
  90614. namespace PhpCsFixer\RuleSet;
  90615. interface RuleSetDescriptionInterface
  90616. {
  90617. public function getDescription(): string;
  90618. public function getName(): string;
  90619. public function getRules(): array;
  90620. public function isRisky(): bool;
  90621. }
  90622. <?php
  90623. declare(strict_types=1);
  90624. namespace PhpCsFixer\RuleSet;
  90625. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  90626. use PhpCsFixer\Utils;
  90627. /**
  90628. @readonly
  90629. */
  90630. final class RuleSet implements RuleSetInterface
  90631. {
  90632. private array $rules;
  90633. public function __construct(array $set = [])
  90634. {
  90635. foreach ($set as $name => $value) {
  90636. if ('' === $name) {
  90637. throw new \InvalidArgumentException('Rule/set name must not be empty.');
  90638. }
  90639. if (\is_int($name)) {
  90640. throw new \InvalidArgumentException(\sprintf('Missing value for "%s" rule/set.', $value));
  90641. }
  90642. if (!\is_bool($value) && !\is_array($value)) {
  90643. $message = str_starts_with($name, '@') ? 'Set must be enabled (true) or disabled (false). Other values are not allowed.' : 'Rule must be enabled (true), disabled (false) or configured (non-empty, assoc array). Other values are not allowed.';
  90644. if (null === $value) {
  90645. $message .= ' To disable the '.(str_starts_with($name, '@') ? 'set' : 'rule').', use "FALSE" instead of "NULL".';
  90646. }
  90647. throw new InvalidFixerConfigurationException($name, $message);
  90648. }
  90649. }
  90650. $this->rules = $this->resolveSet($set);
  90651. }
  90652. public function hasRule(string $rule): bool
  90653. {
  90654. return \array_key_exists($rule, $this->rules);
  90655. }
  90656. public function getRuleConfiguration(string $rule): ?array
  90657. {
  90658. if (!$this->hasRule($rule)) {
  90659. throw new \InvalidArgumentException(\sprintf('Rule "%s" is not in the set.', $rule));
  90660. }
  90661. if (true === $this->rules[$rule]) {
  90662. return null;
  90663. }
  90664. return $this->rules[$rule];
  90665. }
  90666. public function getRules(): array
  90667. {
  90668. return $this->rules;
  90669. }
  90670. private function resolveSet(array $rules): array
  90671. {
  90672. $resolvedRules = [];
  90673. foreach ($rules as $name => $value) {
  90674. if (str_starts_with($name, '@')) {
  90675. if (!\is_bool($value)) {
  90676. throw new \UnexpectedValueException(\sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
  90677. }
  90678. $set = $this->resolveSubset($name, $value);
  90679. $resolvedRules = array_merge($resolvedRules, $set);
  90680. } else {
  90681. $resolvedRules[$name] = $value;
  90682. }
  90683. }
  90684. $resolvedRules = array_filter(
  90685. $resolvedRules,
  90686. static fn ($value): bool => false !== $value
  90687. );
  90688. return $resolvedRules;
  90689. }
  90690. private function resolveSubset(string $setName, bool $setValue): array
  90691. {
  90692. $ruleSet = RuleSets::getSetDefinition($setName);
  90693. if ($ruleSet instanceof DeprecatedRuleSetDescriptionInterface) {
  90694. $messageEnd = [] === $ruleSet->getSuccessorsNames()
  90695. ? 'No replacement available'
  90696. : \sprintf('Use %s instead', Utils::naturalLanguageJoin($ruleSet->getSuccessorsNames()));
  90697. Utils::triggerDeprecation(new \RuntimeException("Rule set \"{$setName}\" is deprecated. {$messageEnd}."));
  90698. }
  90699. $rules = $ruleSet->getRules();
  90700. foreach ($rules as $name => $value) {
  90701. if (str_starts_with($name, '@')) {
  90702. $set = $this->resolveSubset($name, $setValue);
  90703. unset($rules[$name]);
  90704. $rules = array_merge($rules, $set);
  90705. } elseif (!$setValue) {
  90706. $rules[$name] = false;
  90707. } else {
  90708. $rules[$name] = $value;
  90709. }
  90710. }
  90711. return $rules;
  90712. }
  90713. }
  90714. <?php
  90715. declare(strict_types=1);
  90716. namespace PhpCsFixer\RuleSet;
  90717. interface DeprecatedRuleSetDescriptionInterface extends RuleSetDescriptionInterface
  90718. {
  90719. public function getSuccessorsNames(): array;
  90720. }
  90721. <?php
  90722. declare(strict_types=1);
  90723. namespace PhpCsFixer\RuleSet\Sets;
  90724. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  90725. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  90726. final class PHPUnit32MigrationRiskySet extends AbstractMigrationSetDescription
  90727. {
  90728. public function getRules(): array
  90729. {
  90730. return [
  90731. '@PHPUnit30Migration:risky' => true,
  90732. 'php_unit_no_expectation_annotation' => [
  90733. 'target' => PhpUnitTargetVersion::VERSION_3_2,
  90734. ],
  90735. ];
  90736. }
  90737. }
  90738. <?php
  90739. declare(strict_types=1);
  90740. namespace PhpCsFixer\RuleSet\Sets;
  90741. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  90742. final class PHP80MigrationSet extends AbstractMigrationSetDescription
  90743. {
  90744. public function getRules(): array
  90745. {
  90746. return [
  90747. '@PHP74Migration' => true,
  90748. 'clean_namespace' => true,
  90749. 'no_unset_cast' => true,
  90750. ];
  90751. }
  90752. }
  90753. <?php
  90754. declare(strict_types=1);
  90755. namespace PhpCsFixer\RuleSet\Sets;
  90756. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  90757. final class SymfonyRiskySet extends AbstractRuleSetDescription
  90758. {
  90759. public function getRules(): array
  90760. {
  90761. return [
  90762. '@PHP56Migration:risky' => true,
  90763. '@PSR12:risky' => true,
  90764. 'array_push' => true,
  90765. 'combine_nested_dirname' => true,
  90766. 'dir_constant' => true,
  90767. 'ereg_to_preg' => true,
  90768. 'error_suppression' => true,
  90769. 'fopen_flag_order' => true,
  90770. 'fopen_flags' => [
  90771. 'b_mode' => false,
  90772. ],
  90773. 'function_to_constant' => true,
  90774. 'get_class_to_class_keyword' => true,
  90775. 'implode_call' => true,
  90776. 'is_null' => true,
  90777. 'logical_operators' => true,
  90778. 'long_to_shorthand_operator' => true,
  90779. 'modernize_strpos' => true,
  90780. 'modernize_types_casting' => true,
  90781. 'native_constant_invocation' => ['strict' => false],
  90782. 'native_function_invocation' => [
  90783. 'include' => [
  90784. '@compiler_optimized',
  90785. ],
  90786. 'scope' => 'namespaced',
  90787. 'strict' => true,
  90788. ],
  90789. 'no_alias_functions' => true,
  90790. 'no_homoglyph_names' => true,
  90791. 'no_php4_constructor' => true,
  90792. 'no_unneeded_final_method' => true,
  90793. 'no_useless_sprintf' => true,
  90794. 'non_printable_character' => true,
  90795. 'ordered_traits' => true,
  90796. 'php_unit_construct' => true,
  90797. 'php_unit_mock_short_will_return' => true,
  90798. 'php_unit_set_up_tear_down_visibility' => true,
  90799. 'php_unit_test_annotation' => true,
  90800. 'psr_autoloading' => true,
  90801. 'self_accessor' => true,
  90802. 'set_type_to_cast' => true,
  90803. 'string_length_to_empty' => true,
  90804. 'string_line_ending' => true,
  90805. 'ternary_to_elvis_operator' => true,
  90806. ];
  90807. }
  90808. public function getDescription(): string
  90809. {
  90810. return 'Rules that follow the official `Symfony Coding Standards <https://symfony.com/doc/current/contributing/code/standards.html>`_.';
  90811. }
  90812. }
  90813. <?php
  90814. declare(strict_types=1);
  90815. namespace PhpCsFixer\RuleSet\Sets;
  90816. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  90817. final class PhpCsFixerSet extends AbstractRuleSetDescription
  90818. {
  90819. public function getRules(): array
  90820. {
  90821. return [
  90822. '@PER-CS' => true,
  90823. '@Symfony' => true,
  90824. 'blank_line_before_statement' => [
  90825. 'statements' => [
  90826. 'break',
  90827. 'case',
  90828. 'continue',
  90829. 'declare',
  90830. 'default',
  90831. 'exit',
  90832. 'goto',
  90833. 'include',
  90834. 'include_once',
  90835. 'phpdoc',
  90836. 'require',
  90837. 'require_once',
  90838. 'return',
  90839. 'switch',
  90840. 'throw',
  90841. 'try',
  90842. 'yield',
  90843. 'yield_from',
  90844. ],
  90845. ],
  90846. 'combine_consecutive_issets' => true,
  90847. 'combine_consecutive_unsets' => true,
  90848. 'empty_loop_body' => true,
  90849. 'explicit_indirect_variable' => true,
  90850. 'explicit_string_variable' => true,
  90851. 'fully_qualified_strict_types' => [
  90852. 'import_symbols' => true,
  90853. ],
  90854. 'heredoc_to_nowdoc' => true,
  90855. 'method_argument_space' => [
  90856. 'on_multiline' => 'ensure_fully_multiline',
  90857. ],
  90858. 'method_chaining_indentation' => true,
  90859. 'multiline_comment_opening_closing' => true,
  90860. 'multiline_whitespace_before_semicolons' => [
  90861. 'strategy' => 'new_line_for_chained_calls',
  90862. ],
  90863. 'no_extra_blank_lines' => [
  90864. 'tokens' => [
  90865. 'attribute',
  90866. 'break',
  90867. 'case',
  90868. 'continue',
  90869. 'curly_brace_block',
  90870. 'default',
  90871. 'extra',
  90872. 'parenthesis_brace_block',
  90873. 'return',
  90874. 'square_brace_block',
  90875. 'switch',
  90876. 'throw',
  90877. 'use',
  90878. ],
  90879. ],
  90880. 'no_superfluous_elseif' => true,
  90881. 'no_superfluous_phpdoc_tags' => [
  90882. 'allow_mixed' => true,
  90883. 'remove_inheritdoc' => true,
  90884. ],
  90885. 'no_unneeded_control_parentheses' => [
  90886. 'statements' => [
  90887. 'break',
  90888. 'clone',
  90889. 'continue',
  90890. 'echo_print',
  90891. 'negative_instanceof',
  90892. 'others',
  90893. 'return',
  90894. 'switch_case',
  90895. 'yield',
  90896. 'yield_from',
  90897. ],
  90898. ],
  90899. 'no_useless_else' => true,
  90900. 'no_useless_return' => true,
  90901. 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
  90902. 'operator_linebreak' => true,
  90903. 'ordered_class_elements' => true,
  90904. 'ordered_types' => true,
  90905. 'php_unit_data_provider_method_order' => true,
  90906. 'php_unit_internal_class' => true,
  90907. 'php_unit_test_class_requires_covers' => true,
  90908. 'phpdoc_add_missing_param_annotation' => true,
  90909. 'phpdoc_no_empty_return' => true,
  90910. 'phpdoc_order_by_value' => true,
  90911. 'phpdoc_types_order' => true,
  90912. 'phpdoc_var_annotation_correct_order' => true,
  90913. 'protected_to_private' => true,
  90914. 'return_assignment' => true,
  90915. 'self_static_accessor' => true,
  90916. 'single_line_comment_style' => true,
  90917. 'single_line_empty_body' => true,
  90918. 'single_line_throw' => false,
  90919. 'string_implicit_backslashes' => true,
  90920. 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['array_destructuring', 'arrays']],
  90921. 'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
  90922. ];
  90923. }
  90924. public function getDescription(): string
  90925. {
  90926. return 'Rule set as used by the PHP-CS-Fixer development team, highly opinionated.';
  90927. }
  90928. }
  90929. <?php
  90930. declare(strict_types=1);
  90931. namespace PhpCsFixer\RuleSet\Sets;
  90932. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  90933. final class PSR2Set extends AbstractRuleSetDescription
  90934. {
  90935. public function getRules(): array
  90936. {
  90937. return [
  90938. '@PSR1' => true,
  90939. 'blank_line_after_namespace' => true,
  90940. 'braces_position' => true,
  90941. 'class_definition' => true,
  90942. 'constant_case' => true,
  90943. 'control_structure_braces' => true,
  90944. 'control_structure_continuation_position' => true,
  90945. 'elseif' => true,
  90946. 'function_declaration' => true,
  90947. 'indentation_type' => true,
  90948. 'line_ending' => true,
  90949. 'lowercase_keywords' => true,
  90950. 'method_argument_space' => [
  90951. 'attribute_placement' => 'ignore',
  90952. 'on_multiline' => 'ensure_fully_multiline',
  90953. ],
  90954. 'no_break_comment' => true,
  90955. 'no_closing_tag' => true,
  90956. 'no_multiple_statements_per_line' => true,
  90957. 'no_space_around_double_colon' => true,
  90958. 'no_spaces_after_function_name' => true,
  90959. 'no_trailing_whitespace' => true,
  90960. 'no_trailing_whitespace_in_comment' => true,
  90961. 'single_blank_line_at_eof' => true,
  90962. 'single_class_element_per_statement' => [
  90963. 'elements' => [
  90964. 'property',
  90965. ],
  90966. ],
  90967. 'single_import_per_statement' => true,
  90968. 'single_line_after_imports' => true,
  90969. 'single_space_around_construct' => [
  90970. 'constructs_followed_by_a_single_space' => [
  90971. 'abstract',
  90972. 'as',
  90973. 'case',
  90974. 'catch',
  90975. 'class',
  90976. 'do',
  90977. 'else',
  90978. 'elseif',
  90979. 'final',
  90980. 'for',
  90981. 'foreach',
  90982. 'function',
  90983. 'if',
  90984. 'interface',
  90985. 'namespace',
  90986. 'private',
  90987. 'protected',
  90988. 'public',
  90989. 'static',
  90990. 'switch',
  90991. 'trait',
  90992. 'try',
  90993. 'use_lambda',
  90994. 'while',
  90995. ],
  90996. 'constructs_preceded_by_a_single_space' => [
  90997. 'as',
  90998. 'else',
  90999. 'elseif',
  91000. 'use_lambda',
  91001. ],
  91002. ],
  91003. 'spaces_inside_parentheses' => true,
  91004. 'statement_indentation' => true,
  91005. 'switch_case_semicolon_to_colon' => true,
  91006. 'switch_case_space' => true,
  91007. 'visibility_required' => ['elements' => ['method', 'property']],
  91008. ];
  91009. }
  91010. public function getDescription(): string
  91011. {
  91012. return 'Rules that follow `PSR-2 <https://www.php-fig.org/psr/psr-2/>`_ standard.';
  91013. }
  91014. }
  91015. <?php
  91016. declare(strict_types=1);
  91017. namespace PhpCsFixer\RuleSet\Sets;
  91018. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91019. final class PHP71MigrationRiskySet extends AbstractMigrationSetDescription
  91020. {
  91021. public function getRules(): array
  91022. {
  91023. return [
  91024. '@PHP70Migration:risky' => true,
  91025. 'void_return' => true,
  91026. ];
  91027. }
  91028. }
  91029. <?php
  91030. declare(strict_types=1);
  91031. namespace PhpCsFixer\RuleSet\Sets;
  91032. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91033. final class PHP82MigrationRiskySet extends AbstractMigrationSetDescription
  91034. {
  91035. public function getRules(): array
  91036. {
  91037. return [
  91038. '@PHP80Migration:risky' => true,
  91039. 'phpdoc_readonly_class_comment_to_keyword' => true,
  91040. ];
  91041. }
  91042. }
  91043. <?php
  91044. declare(strict_types=1);
  91045. namespace PhpCsFixer\RuleSet\Sets;
  91046. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91047. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91048. final class PHPUnit56MigrationRiskySet extends AbstractMigrationSetDescription
  91049. {
  91050. public function getRules(): array
  91051. {
  91052. return [
  91053. '@PHPUnit55Migration:risky' => true,
  91054. 'php_unit_dedicate_assert' => [
  91055. 'target' => PhpUnitTargetVersion::VERSION_5_6,
  91056. ],
  91057. 'php_unit_expectation' => [
  91058. 'target' => PhpUnitTargetVersion::VERSION_5_6,
  91059. ],
  91060. ];
  91061. }
  91062. }
  91063. <?php
  91064. declare(strict_types=1);
  91065. namespace PhpCsFixer\RuleSet\Sets;
  91066. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91067. final class PHP54MigrationSet extends AbstractMigrationSetDescription
  91068. {
  91069. public function getRules(): array
  91070. {
  91071. return [
  91072. 'array_syntax' => true,
  91073. ];
  91074. }
  91075. }
  91076. <?php
  91077. declare(strict_types=1);
  91078. namespace PhpCsFixer\RuleSet\Sets;
  91079. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91080. final class PHP70MigrationSet extends AbstractMigrationSetDescription
  91081. {
  91082. public function getRules(): array
  91083. {
  91084. return [
  91085. '@PHP54Migration' => true,
  91086. 'ternary_to_null_coalescing' => true,
  91087. ];
  91088. }
  91089. }
  91090. <?php
  91091. declare(strict_types=1);
  91092. namespace PhpCsFixer\RuleSet\Sets;
  91093. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91094. final class PHP74MigrationRiskySet extends AbstractMigrationSetDescription
  91095. {
  91096. public function getRules(): array
  91097. {
  91098. return [
  91099. '@PHP71Migration:risky' => true,
  91100. 'implode_call' => true,
  91101. 'no_alias_functions' => true,
  91102. 'use_arrow_functions' => true,
  91103. ];
  91104. }
  91105. }
  91106. <?php
  91107. declare(strict_types=1);
  91108. namespace PhpCsFixer\RuleSet\Sets;
  91109. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91110. final class PERCS1x0Set extends AbstractRuleSetDescription
  91111. {
  91112. public function getName(): string
  91113. {
  91114. return '@PER-CS1.0';
  91115. }
  91116. public function getRules(): array
  91117. {
  91118. return [
  91119. '@PSR12' => true,
  91120. ];
  91121. }
  91122. public function getDescription(): string
  91123. {
  91124. return 'Rules that follow `PER Coding Style 1.0 <https://www.php-fig.org/per/coding-style/>`_.';
  91125. }
  91126. }
  91127. <?php
  91128. declare(strict_types=1);
  91129. namespace PhpCsFixer\RuleSet\Sets;
  91130. use PhpCsFixer\Fixer\Phpdoc\PhpdocSeparationFixer;
  91131. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91132. final class SymfonySet extends AbstractRuleSetDescription
  91133. {
  91134. public function getRules(): array
  91135. {
  91136. return [
  91137. '@PER-CS2.0' => true,
  91138. 'align_multiline_comment' => true,
  91139. 'backtick_to_shell_exec' => true,
  91140. 'binary_operator_spaces' => true,
  91141. 'blank_line_before_statement' => [
  91142. 'statements' => [
  91143. 'return',
  91144. ],
  91145. ],
  91146. 'braces_position' => [
  91147. 'allow_single_line_anonymous_functions' => true,
  91148. 'allow_single_line_empty_anonymous_classes' => true,
  91149. ],
  91150. 'class_attributes_separation' => [
  91151. 'elements' => [
  91152. 'method' => 'one',
  91153. ],
  91154. ],
  91155. 'class_definition' => [
  91156. 'single_line' => true,
  91157. ],
  91158. 'class_reference_name_casing' => true,
  91159. 'clean_namespace' => true,
  91160. 'concat_space' => true,
  91161. 'declare_parentheses' => true,
  91162. 'echo_tag_syntax' => true,
  91163. 'empty_loop_body' => ['style' => 'braces'],
  91164. 'empty_loop_condition' => true,
  91165. 'fully_qualified_strict_types' => true,
  91166. 'function_declaration' => true,
  91167. 'general_phpdoc_tag_rename' => [
  91168. 'replacements' => [
  91169. 'inheritDocs' => 'inheritDoc',
  91170. ],
  91171. ],
  91172. 'global_namespace_import' => [
  91173. 'import_classes' => false,
  91174. 'import_constants' => false,
  91175. 'import_functions' => false,
  91176. ],
  91177. 'include' => true,
  91178. 'increment_style' => true,
  91179. 'integer_literal_case' => true,
  91180. 'lambda_not_used_import' => true,
  91181. 'linebreak_after_opening_tag' => true,
  91182. 'magic_constant_casing' => true,
  91183. 'magic_method_casing' => true,
  91184. 'method_argument_space' => [
  91185. 'on_multiline' => 'ignore',
  91186. ],
  91187. 'native_function_casing' => true,
  91188. 'native_type_declaration_casing' => true,
  91189. 'no_alias_language_construct_call' => true,
  91190. 'no_alternative_syntax' => true,
  91191. 'no_binary_string' => true,
  91192. 'no_blank_lines_after_phpdoc' => true,
  91193. 'no_empty_comment' => true,
  91194. 'no_empty_phpdoc' => true,
  91195. 'no_empty_statement' => true,
  91196. 'no_extra_blank_lines' => [
  91197. 'tokens' => [
  91198. 'attribute',
  91199. 'case',
  91200. 'continue',
  91201. 'curly_brace_block',
  91202. 'default',
  91203. 'extra',
  91204. 'parenthesis_brace_block',
  91205. 'square_brace_block',
  91206. 'switch',
  91207. 'throw',
  91208. 'use',
  91209. ],
  91210. ],
  91211. 'no_leading_namespace_whitespace' => true,
  91212. 'no_mixed_echo_print' => true,
  91213. 'no_multiline_whitespace_around_double_arrow' => true,
  91214. 'no_null_property_initialization' => true,
  91215. 'no_short_bool_cast' => true,
  91216. 'no_singleline_whitespace_before_semicolons' => true,
  91217. 'no_spaces_around_offset' => true,
  91218. 'no_superfluous_phpdoc_tags' => [
  91219. 'allow_hidden_params' => true,
  91220. 'remove_inheritdoc' => true,
  91221. ],
  91222. 'no_trailing_comma_in_singleline' => true,
  91223. 'no_unneeded_braces' => [
  91224. 'namespaces' => true,
  91225. ],
  91226. 'no_unneeded_control_parentheses' => [
  91227. 'statements' => [
  91228. 'break',
  91229. 'clone',
  91230. 'continue',
  91231. 'echo_print',
  91232. 'others',
  91233. 'return',
  91234. 'switch_case',
  91235. 'yield',
  91236. 'yield_from',
  91237. ],
  91238. ],
  91239. 'no_unneeded_import_alias' => true,
  91240. 'no_unset_cast' => true,
  91241. 'no_unused_imports' => true,
  91242. 'no_useless_concat_operator' => true,
  91243. 'no_useless_nullsafe_operator' => true,
  91244. 'no_whitespace_before_comma_in_array' => true,
  91245. 'normalize_index_brace' => true,
  91246. 'nullable_type_declaration' => true,
  91247. 'nullable_type_declaration_for_default_null_value' => true,
  91248. 'object_operator_without_whitespace' => true,
  91249. 'operator_linebreak' => [
  91250. 'only_booleans' => true,
  91251. ],
  91252. 'ordered_imports' => [
  91253. 'imports_order' => [
  91254. 'class',
  91255. 'function',
  91256. 'const',
  91257. ],
  91258. 'sort_algorithm' => 'alpha',
  91259. ],
  91260. 'ordered_types' => [
  91261. 'null_adjustment' => 'always_last',
  91262. 'sort_algorithm' => 'none',
  91263. ],
  91264. 'php_unit_fqcn_annotation' => true,
  91265. 'php_unit_method_casing' => true,
  91266. 'phpdoc_align' => true,
  91267. 'phpdoc_annotation_without_dot' => true,
  91268. 'phpdoc_indent' => true,
  91269. 'phpdoc_inline_tag_normalizer' => true,
  91270. 'phpdoc_no_access' => true,
  91271. 'phpdoc_no_alias_tag' => true,
  91272. 'phpdoc_no_package' => true,
  91273. 'phpdoc_no_useless_inheritdoc' => true,
  91274. 'phpdoc_order' => [
  91275. 'order' => [
  91276. 'param',
  91277. 'return',
  91278. 'throws',
  91279. ],
  91280. ],
  91281. 'phpdoc_return_self_reference' => true,
  91282. 'phpdoc_scalar' => true,
  91283. 'phpdoc_separation' => [
  91284. 'groups' => [
  91285. ['Annotation', 'NamedArgumentConstructor', 'Target'],
  91286. ...PhpdocSeparationFixer::OPTION_GROUPS_DEFAULT,
  91287. ],
  91288. ],
  91289. 'phpdoc_single_line_var_spacing' => true,
  91290. 'phpdoc_summary' => true,
  91291. 'phpdoc_tag_type' => [
  91292. 'tags' => [
  91293. 'inheritDoc' => 'inline',
  91294. ],
  91295. ],
  91296. 'phpdoc_to_comment' => true,
  91297. 'phpdoc_trim' => true,
  91298. 'phpdoc_trim_consecutive_blank_line_separation' => true,
  91299. 'phpdoc_types' => true,
  91300. 'phpdoc_types_order' => [
  91301. 'null_adjustment' => 'always_last',
  91302. 'sort_algorithm' => 'none',
  91303. ],
  91304. 'phpdoc_var_without_name' => true,
  91305. 'semicolon_after_instruction' => true,
  91306. 'simple_to_complex_string_variable' => true,
  91307. 'single_class_element_per_statement' => true,
  91308. 'single_import_per_statement' => true,
  91309. 'single_line_comment_spacing' => true,
  91310. 'single_line_comment_style' => [
  91311. 'comment_types' => [
  91312. 'hash',
  91313. ],
  91314. ],
  91315. 'single_line_empty_body' => false,
  91316. 'single_line_throw' => true,
  91317. 'single_quote' => true,
  91318. 'single_space_around_construct' => true,
  91319. 'space_after_semicolon' => [
  91320. 'remove_in_empty_for_expressions' => true,
  91321. ],
  91322. 'standardize_increment' => true,
  91323. 'standardize_not_equals' => true,
  91324. 'statement_indentation' => [
  91325. 'stick_comment_to_next_continuous_control_statement' => true,
  91326. ],
  91327. 'switch_continue_to_break' => true,
  91328. 'trailing_comma_in_multiline' => [
  91329. 'after_heredoc' => true,
  91330. 'elements' => [
  91331. 'array_destructuring',
  91332. 'arrays',
  91333. 'match',
  91334. 'parameters',
  91335. ],
  91336. ],
  91337. 'trim_array_spaces' => true,
  91338. 'type_declaration_spaces' => true,
  91339. 'types_spaces' => true,
  91340. 'unary_operator_spaces' => true,
  91341. 'whitespace_after_comma_in_array' => true,
  91342. 'yoda_style' => true,
  91343. ];
  91344. }
  91345. public function getDescription(): string
  91346. {
  91347. return 'Rules that follow the official `Symfony Coding Standards <https://symfony.com/doc/current/contributing/code/standards.html>`_.';
  91348. }
  91349. }
  91350. <?php
  91351. declare(strict_types=1);
  91352. namespace PhpCsFixer\RuleSet\Sets;
  91353. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91354. final class PERCSSet extends AbstractRuleSetDescription
  91355. {
  91356. public function getName(): string
  91357. {
  91358. return '@PER-CS';
  91359. }
  91360. public function getRules(): array
  91361. {
  91362. return [
  91363. '@PER-CS2.0' => true,
  91364. ];
  91365. }
  91366. public function getDescription(): string
  91367. {
  91368. return 'Alias for the latest revision of PER-CS rules. Use it if you always want to be in sync with newest PER-CS standard.';
  91369. }
  91370. }
  91371. <?php
  91372. declare(strict_types=1);
  91373. namespace PhpCsFixer\RuleSet\Sets;
  91374. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91375. final class PSR12Set extends AbstractRuleSetDescription
  91376. {
  91377. public function getRules(): array
  91378. {
  91379. return [
  91380. '@PSR2' => true,
  91381. 'binary_operator_spaces' => [
  91382. 'default' => 'at_least_single_space',
  91383. ],
  91384. 'blank_line_after_opening_tag' => true,
  91385. 'blank_line_between_import_groups' => true,
  91386. 'blank_lines_before_namespace' => true,
  91387. 'braces_position' => [
  91388. 'allow_single_line_empty_anonymous_classes' => true,
  91389. ],
  91390. 'class_definition' => [
  91391. 'inline_constructor_arguments' => false,
  91392. 'space_before_parenthesis' => true,
  91393. ],
  91394. 'compact_nullable_type_declaration' => true,
  91395. 'declare_equal_normalize' => true,
  91396. 'lowercase_cast' => true,
  91397. 'lowercase_static_reference' => true,
  91398. 'new_with_parentheses' => true,
  91399. 'no_blank_lines_after_class_opening' => true,
  91400. 'no_extra_blank_lines' => [
  91401. 'tokens' => [
  91402. 'use',
  91403. ],
  91404. ],
  91405. 'no_leading_import_slash' => true,
  91406. 'no_whitespace_in_blank_line' => true,
  91407. 'ordered_class_elements' => [
  91408. 'order' => [
  91409. 'use_trait',
  91410. ],
  91411. ],
  91412. 'ordered_imports' => [
  91413. 'imports_order' => [
  91414. 'class',
  91415. 'function',
  91416. 'const',
  91417. ],
  91418. 'sort_algorithm' => 'none',
  91419. ],
  91420. 'return_type_declaration' => true,
  91421. 'short_scalar_cast' => true,
  91422. 'single_import_per_statement' => ['group_to_single_imports' => false],
  91423. 'single_space_around_construct' => [
  91424. 'constructs_followed_by_a_single_space' => [
  91425. 'abstract',
  91426. 'as',
  91427. 'case',
  91428. 'catch',
  91429. 'class',
  91430. 'const_import',
  91431. 'do',
  91432. 'else',
  91433. 'elseif',
  91434. 'final',
  91435. 'finally',
  91436. 'for',
  91437. 'foreach',
  91438. 'function',
  91439. 'function_import',
  91440. 'if',
  91441. 'insteadof',
  91442. 'interface',
  91443. 'namespace',
  91444. 'new',
  91445. 'private',
  91446. 'protected',
  91447. 'public',
  91448. 'static',
  91449. 'switch',
  91450. 'trait',
  91451. 'try',
  91452. 'use',
  91453. 'use_lambda',
  91454. 'while',
  91455. ],
  91456. 'constructs_preceded_by_a_single_space' => [
  91457. 'as',
  91458. 'else',
  91459. 'elseif',
  91460. 'use_lambda',
  91461. ],
  91462. ],
  91463. 'single_trait_insert_per_statement' => true,
  91464. 'ternary_operator_spaces' => true,
  91465. 'unary_operator_spaces' => [
  91466. 'only_dec_inc' => true,
  91467. ],
  91468. 'visibility_required' => true,
  91469. ];
  91470. }
  91471. public function getDescription(): string
  91472. {
  91473. return 'Rules that follow `PSR-12 <https://www.php-fig.org/psr/psr-12/>`_ standard.';
  91474. }
  91475. }
  91476. <?php
  91477. declare(strict_types=1);
  91478. namespace PhpCsFixer\RuleSet\Sets;
  91479. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91480. final class PHP71MigrationSet extends AbstractMigrationSetDescription
  91481. {
  91482. public function getRules(): array
  91483. {
  91484. return [
  91485. '@PHP70Migration' => true,
  91486. 'list_syntax' => true,
  91487. 'visibility_required' => true,
  91488. ];
  91489. }
  91490. }
  91491. <?php
  91492. declare(strict_types=1);
  91493. namespace PhpCsFixer\RuleSet\Sets;
  91494. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91495. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91496. final class PHPUnit84MigrationRiskySet extends AbstractMigrationSetDescription
  91497. {
  91498. public function getRules(): array
  91499. {
  91500. return [
  91501. '@PHPUnit60Migration:risky' => true,
  91502. '@PHPUnit75Migration:risky' => true,
  91503. 'php_unit_expectation' => [
  91504. 'target' => PhpUnitTargetVersion::VERSION_8_4,
  91505. ],
  91506. ];
  91507. }
  91508. }
  91509. <?php
  91510. declare(strict_types=1);
  91511. namespace PhpCsFixer\RuleSet\Sets;
  91512. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91513. final class PHP81MigrationSet extends AbstractMigrationSetDescription
  91514. {
  91515. public function getRules(): array
  91516. {
  91517. return [
  91518. '@PHP80Migration' => true,
  91519. 'octal_notation' => true,
  91520. ];
  91521. }
  91522. }
  91523. <?php
  91524. declare(strict_types=1);
  91525. namespace PhpCsFixer\RuleSet\Sets;
  91526. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91527. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91528. final class PHPUnit60MigrationRiskySet extends AbstractMigrationSetDescription
  91529. {
  91530. public function getRules(): array
  91531. {
  91532. return [
  91533. '@PHPUnit57Migration:risky' => true,
  91534. 'php_unit_namespaced' => [
  91535. 'target' => PhpUnitTargetVersion::VERSION_6_0,
  91536. ],
  91537. ];
  91538. }
  91539. }
  91540. <?php
  91541. declare(strict_types=1);
  91542. namespace PhpCsFixer\RuleSet\Sets;
  91543. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91544. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91545. final class PHPUnit57MigrationRiskySet extends AbstractMigrationSetDescription
  91546. {
  91547. public function getRules(): array
  91548. {
  91549. return [
  91550. '@PHPUnit56Migration:risky' => true,
  91551. 'php_unit_namespaced' => [
  91552. 'target' => PhpUnitTargetVersion::VERSION_5_7,
  91553. ],
  91554. ];
  91555. }
  91556. }
  91557. <?php
  91558. declare(strict_types=1);
  91559. namespace PhpCsFixer\RuleSet\Sets;
  91560. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91561. final class PHP70MigrationRiskySet extends AbstractMigrationSetDescription
  91562. {
  91563. public function getRules(): array
  91564. {
  91565. return [
  91566. '@PHP56Migration:risky' => true,
  91567. 'combine_nested_dirname' => true,
  91568. 'declare_strict_types' => true,
  91569. 'non_printable_character' => true,
  91570. 'random_api_migration' => [
  91571. 'replacements' => [
  91572. 'mt_rand' => 'random_int',
  91573. 'rand' => 'random_int',
  91574. ],
  91575. ],
  91576. ];
  91577. }
  91578. }
  91579. <?php
  91580. declare(strict_types=1);
  91581. namespace PhpCsFixer\RuleSet\Sets;
  91582. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91583. use PhpCsFixer\RuleSet\DeprecatedRuleSetDescriptionInterface;
  91584. final class PERRiskySet extends AbstractRuleSetDescription implements DeprecatedRuleSetDescriptionInterface
  91585. {
  91586. public function getName(): string
  91587. {
  91588. return '@PER:risky';
  91589. }
  91590. public function getRules(): array
  91591. {
  91592. return [
  91593. '@PER-CS:risky' => true,
  91594. ];
  91595. }
  91596. public function getDescription(): string
  91597. {
  91598. return 'Alias for the newest PER-CS risky rules. It is recommended you use ``@PER-CS2.0:risky`` instead if you want to stick with stable ruleset.';
  91599. }
  91600. public function getSuccessorsNames(): array
  91601. {
  91602. return ['@PER-CS:risky'];
  91603. }
  91604. }
  91605. <?php
  91606. declare(strict_types=1);
  91607. namespace PhpCsFixer\RuleSet\Sets;
  91608. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91609. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91610. final class PHPUnit52MigrationRiskySet extends AbstractMigrationSetDescription
  91611. {
  91612. public function getRules(): array
  91613. {
  91614. return [
  91615. '@PHPUnit50Migration:risky' => true,
  91616. 'php_unit_expectation' => [
  91617. 'target' => PhpUnitTargetVersion::VERSION_5_2,
  91618. ],
  91619. ];
  91620. }
  91621. }
  91622. <?php
  91623. declare(strict_types=1);
  91624. namespace PhpCsFixer\RuleSet\Sets;
  91625. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91626. final class DoctrineAnnotationSet extends AbstractRuleSetDescription
  91627. {
  91628. public function getRules(): array
  91629. {
  91630. return [
  91631. 'doctrine_annotation_array_assignment' => [
  91632. 'operator' => ':',
  91633. ],
  91634. 'doctrine_annotation_braces' => true,
  91635. 'doctrine_annotation_indentation' => true,
  91636. 'doctrine_annotation_spaces' => [
  91637. 'before_array_assignments_colon' => false,
  91638. ],
  91639. ];
  91640. }
  91641. public function getDescription(): string
  91642. {
  91643. return 'Rules covering Doctrine annotations with configuration based on examples found in `Doctrine Annotation documentation <https://www.doctrine-project.org/projects/doctrine-annotations/en/latest/annotations.html>`_ and `Symfony documentation <https://symfony.com/doc/master/bundles/SensioFrameworkExtraBundle/annotations/routing.html>`_.';
  91644. }
  91645. }
  91646. <?php
  91647. declare(strict_types=1);
  91648. namespace PhpCsFixer\RuleSet\Sets;
  91649. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91650. final class PERCS2x0Set extends AbstractRuleSetDescription
  91651. {
  91652. public function getName(): string
  91653. {
  91654. return '@PER-CS2.0';
  91655. }
  91656. public function getRules(): array
  91657. {
  91658. return [
  91659. '@PER-CS1.0' => true,
  91660. 'array_indentation' => true,
  91661. 'array_syntax' => true,
  91662. 'cast_spaces' => true,
  91663. 'concat_space' => ['spacing' => 'one'],
  91664. 'function_declaration' => [
  91665. 'closure_fn_spacing' => 'none',
  91666. ],
  91667. 'method_argument_space' => true,
  91668. 'new_with_parentheses' => [
  91669. 'anonymous_class' => false,
  91670. ],
  91671. 'single_line_empty_body' => true,
  91672. 'single_space_around_construct' => [
  91673. 'constructs_followed_by_a_single_space' => [
  91674. 'abstract',
  91675. 'as',
  91676. 'case',
  91677. 'catch',
  91678. 'class',
  91679. 'const',
  91680. 'const_import',
  91681. 'do',
  91682. 'else',
  91683. 'elseif',
  91684. 'enum',
  91685. 'final',
  91686. 'finally',
  91687. 'for',
  91688. 'foreach',
  91689. 'function',
  91690. 'function_import',
  91691. 'if',
  91692. 'insteadof',
  91693. 'interface',
  91694. 'match',
  91695. 'named_argument',
  91696. 'namespace',
  91697. 'new',
  91698. 'private',
  91699. 'protected',
  91700. 'public',
  91701. 'readonly',
  91702. 'static',
  91703. 'switch',
  91704. 'trait',
  91705. 'try',
  91706. 'type_colon',
  91707. 'use',
  91708. 'use_lambda',
  91709. 'while',
  91710. ],
  91711. 'constructs_preceded_by_a_single_space' => [
  91712. 'as',
  91713. 'else',
  91714. 'elseif',
  91715. 'use_lambda',
  91716. ],
  91717. ],
  91718. 'trailing_comma_in_multiline' => [
  91719. 'after_heredoc' => true,
  91720. 'elements' => [
  91721. 'arguments',
  91722. 'array_destructuring',
  91723. 'arrays',
  91724. 'match',
  91725. 'parameters',
  91726. ],
  91727. ],
  91728. ];
  91729. }
  91730. public function getDescription(): string
  91731. {
  91732. return 'Rules that follow `PER Coding Style 2.0 <https://www.php-fig.org/per/coding-style/>`_.';
  91733. }
  91734. }
  91735. <?php
  91736. declare(strict_types=1);
  91737. namespace PhpCsFixer\RuleSet\Sets;
  91738. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91739. final class PhpCsFixerRiskySet extends AbstractRuleSetDescription
  91740. {
  91741. public function getRules(): array
  91742. {
  91743. return [
  91744. '@PER-CS:risky' => true,
  91745. '@Symfony:risky' => true,
  91746. 'comment_to_phpdoc' => true,
  91747. 'final_internal_class' => true,
  91748. 'get_class_to_class_keyword' => false,
  91749. 'modernize_strpos' => false,
  91750. 'native_constant_invocation' => [
  91751. 'fix_built_in' => false,
  91752. 'include' => [
  91753. 'DIRECTORY_SEPARATOR',
  91754. 'PHP_INT_SIZE',
  91755. 'PHP_SAPI',
  91756. 'PHP_VERSION_ID',
  91757. ],
  91758. 'scope' => 'namespaced',
  91759. 'strict' => true,
  91760. ],
  91761. 'no_alias_functions' => [
  91762. 'sets' => [
  91763. '@all',
  91764. ],
  91765. ],
  91766. 'no_unset_on_property' => true,
  91767. 'php_unit_data_provider_name' => true,
  91768. 'php_unit_data_provider_return_type' => true,
  91769. 'php_unit_data_provider_static' => ['force' => true],
  91770. 'php_unit_strict' => true,
  91771. 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
  91772. 'static_lambda' => true,
  91773. 'strict_comparison' => true,
  91774. 'strict_param' => true,
  91775. 'yield_from_array_to_yields' => true,
  91776. ];
  91777. }
  91778. public function getDescription(): string
  91779. {
  91780. return 'Rule set as used by the PHP-CS-Fixer development team, highly opinionated.';
  91781. }
  91782. }
  91783. <?php
  91784. declare(strict_types=1);
  91785. namespace PhpCsFixer\RuleSet\Sets;
  91786. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91787. final class PHP73MigrationSet extends AbstractMigrationSetDescription
  91788. {
  91789. public function getRules(): array
  91790. {
  91791. return [
  91792. '@PHP71Migration' => true,
  91793. 'heredoc_indentation' => true,
  91794. 'method_argument_space' => ['after_heredoc' => true],
  91795. 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
  91796. 'trailing_comma_in_multiline' => ['after_heredoc' => true],
  91797. ];
  91798. }
  91799. }
  91800. <?php
  91801. declare(strict_types=1);
  91802. namespace PhpCsFixer\RuleSet\Sets;
  91803. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91804. final class PHP80MigrationRiskySet extends AbstractMigrationSetDescription
  91805. {
  91806. public function getRules(): array
  91807. {
  91808. return [
  91809. '@PHP74Migration:risky' => true,
  91810. 'get_class_to_class_keyword' => true,
  91811. 'modernize_strpos' => true,
  91812. 'no_alias_functions' => [
  91813. 'sets' => [
  91814. '@all',
  91815. ],
  91816. ],
  91817. 'no_php4_constructor' => true,
  91818. 'no_unneeded_final_method' => true,
  91819. 'no_unreachable_default_argument_value' => true,
  91820. ];
  91821. }
  91822. }
  91823. <?php
  91824. declare(strict_types=1);
  91825. namespace PhpCsFixer\RuleSet\Sets;
  91826. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91827. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91828. final class PHPUnit54MigrationRiskySet extends AbstractMigrationSetDescription
  91829. {
  91830. public function getRules(): array
  91831. {
  91832. return [
  91833. '@PHPUnit52Migration:risky' => true,
  91834. 'php_unit_mock' => [
  91835. 'target' => PhpUnitTargetVersion::VERSION_5_4,
  91836. ],
  91837. ];
  91838. }
  91839. }
  91840. <?php
  91841. declare(strict_types=1);
  91842. namespace PhpCsFixer\RuleSet\Sets;
  91843. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91844. final class PHP84MigrationSet extends AbstractMigrationSetDescription
  91845. {
  91846. public function getRules(): array
  91847. {
  91848. return [
  91849. '@PHP83Migration' => true,
  91850. 'nullable_type_declaration_for_default_null_value' => true,
  91851. ];
  91852. }
  91853. }
  91854. <?php
  91855. declare(strict_types=1);
  91856. namespace PhpCsFixer\RuleSet\Sets;
  91857. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91858. final class PERCSRiskySet extends AbstractRuleSetDescription
  91859. {
  91860. public function getName(): string
  91861. {
  91862. return '@PER-CS:risky';
  91863. }
  91864. public function getRules(): array
  91865. {
  91866. return [
  91867. '@PER-CS2.0:risky' => true,
  91868. ];
  91869. }
  91870. public function getDescription(): string
  91871. {
  91872. return 'Alias for the latest revision of PER-CS risky rules. Use it if you always want to be in sync with newest PER-CS standard.';
  91873. }
  91874. }
  91875. <?php
  91876. declare(strict_types=1);
  91877. namespace PhpCsFixer\RuleSet\Sets;
  91878. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91879. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91880. final class PHPUnit35MigrationRiskySet extends AbstractMigrationSetDescription
  91881. {
  91882. public function getRules(): array
  91883. {
  91884. return [
  91885. '@PHPUnit32Migration:risky' => true,
  91886. 'php_unit_dedicate_assert' => [
  91887. 'target' => PhpUnitTargetVersion::VERSION_3_5,
  91888. ],
  91889. ];
  91890. }
  91891. }
  91892. <?php
  91893. declare(strict_types=1);
  91894. namespace PhpCsFixer\RuleSet\Sets;
  91895. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91896. final class PHP83MigrationSet extends AbstractMigrationSetDescription
  91897. {
  91898. public function getRules(): array
  91899. {
  91900. return [
  91901. '@PHP82Migration' => true,
  91902. ];
  91903. }
  91904. }
  91905. <?php
  91906. declare(strict_types=1);
  91907. namespace PhpCsFixer\RuleSet\Sets;
  91908. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91909. final class PHP56MigrationRiskySet extends AbstractMigrationSetDescription
  91910. {
  91911. public function getRules(): array
  91912. {
  91913. return [
  91914. 'pow_to_exponentiation' => true,
  91915. ];
  91916. }
  91917. }
  91918. <?php
  91919. declare(strict_types=1);
  91920. namespace PhpCsFixer\RuleSet\Sets;
  91921. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91922. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91923. final class PHPUnit30MigrationRiskySet extends AbstractMigrationSetDescription
  91924. {
  91925. public function getRules(): array
  91926. {
  91927. return [
  91928. 'php_unit_dedicate_assert' => [
  91929. 'target' => PhpUnitTargetVersion::VERSION_3_0,
  91930. ],
  91931. ];
  91932. }
  91933. }
  91934. <?php
  91935. declare(strict_types=1);
  91936. namespace PhpCsFixer\RuleSet\Sets;
  91937. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91938. final class PHPUnit100MigrationRiskySet extends AbstractMigrationSetDescription
  91939. {
  91940. public function getRules(): array
  91941. {
  91942. return [
  91943. '@PHPUnit91Migration:risky' => true,
  91944. 'php_unit_data_provider_static' => ['force' => true],
  91945. ];
  91946. }
  91947. }
  91948. <?php
  91949. declare(strict_types=1);
  91950. namespace PhpCsFixer\RuleSet\Sets;
  91951. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  91952. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91953. final class PHPUnit43MigrationRiskySet extends AbstractMigrationSetDescription
  91954. {
  91955. public function getRules(): array
  91956. {
  91957. return [
  91958. '@PHPUnit35Migration:risky' => true,
  91959. 'php_unit_no_expectation_annotation' => [
  91960. 'target' => PhpUnitTargetVersion::VERSION_4_3,
  91961. ],
  91962. ];
  91963. }
  91964. }
  91965. <?php
  91966. declare(strict_types=1);
  91967. namespace PhpCsFixer\RuleSet\Sets;
  91968. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  91969. final class PHP74MigrationSet extends AbstractMigrationSetDescription
  91970. {
  91971. public function getRules(): array
  91972. {
  91973. return [
  91974. '@PHP73Migration' => true,
  91975. 'assign_null_coalescing_to_coalesce_equal' => true,
  91976. 'normalize_index_brace' => true,
  91977. 'short_scalar_cast' => true,
  91978. ];
  91979. }
  91980. }
  91981. <?php
  91982. declare(strict_types=1);
  91983. namespace PhpCsFixer\RuleSet\Sets;
  91984. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  91985. final class PSR1Set extends AbstractRuleSetDescription
  91986. {
  91987. public function getRules(): array
  91988. {
  91989. return [
  91990. 'encoding' => true,
  91991. 'full_opening_tag' => true,
  91992. ];
  91993. }
  91994. public function getDescription(): string
  91995. {
  91996. return 'Rules that follow `PSR-1 <https://www.php-fig.org/psr/psr-1/>`_ standard.';
  91997. }
  91998. }
  91999. <?php
  92000. declare(strict_types=1);
  92001. namespace PhpCsFixer\RuleSet\Sets;
  92002. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92003. final class PHPUnit91MigrationRiskySet extends AbstractMigrationSetDescription
  92004. {
  92005. public function getRules(): array
  92006. {
  92007. return [
  92008. '@PHPUnit84Migration:risky' => true,
  92009. 'php_unit_assert_new_names' => true,
  92010. ];
  92011. }
  92012. }
  92013. <?php
  92014. declare(strict_types=1);
  92015. namespace PhpCsFixer\RuleSet\Sets;
  92016. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  92017. final class PSR12RiskySet extends AbstractRuleSetDescription
  92018. {
  92019. public function getRules(): array
  92020. {
  92021. return [
  92022. 'no_trailing_whitespace_in_string' => true,
  92023. 'no_unreachable_default_argument_value' => true,
  92024. ];
  92025. }
  92026. public function getDescription(): string
  92027. {
  92028. return 'Rules that follow `PSR-12 <https://www.php-fig.org/psr/psr-12/>`_ standard.';
  92029. }
  92030. }
  92031. <?php
  92032. declare(strict_types=1);
  92033. namespace PhpCsFixer\RuleSet\Sets;
  92034. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92035. final class PHP82MigrationSet extends AbstractMigrationSetDescription
  92036. {
  92037. public function getRules(): array
  92038. {
  92039. return [
  92040. '@PHP81Migration' => true,
  92041. 'simple_to_complex_string_variable' => true,
  92042. ];
  92043. }
  92044. }
  92045. <?php
  92046. declare(strict_types=1);
  92047. namespace PhpCsFixer\RuleSet\Sets;
  92048. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  92049. final class PERCS2x0RiskySet extends AbstractRuleSetDescription
  92050. {
  92051. public function getName(): string
  92052. {
  92053. return '@PER-CS2.0:risky';
  92054. }
  92055. public function getRules(): array
  92056. {
  92057. return [
  92058. '@PER-CS1.0:risky' => true,
  92059. ];
  92060. }
  92061. public function getDescription(): string
  92062. {
  92063. return 'Rules that follow `PER Coding Style 2.0 <https://www.php-fig.org/per/coding-style/>`_.';
  92064. }
  92065. }
  92066. <?php
  92067. declare(strict_types=1);
  92068. namespace PhpCsFixer\RuleSet\Sets;
  92069. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  92070. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92071. final class PHPUnit50MigrationRiskySet extends AbstractMigrationSetDescription
  92072. {
  92073. public function getRules(): array
  92074. {
  92075. return [
  92076. '@PHPUnit48Migration:risky' => true,
  92077. 'php_unit_dedicate_assert' => [
  92078. 'target' => PhpUnitTargetVersion::VERSION_5_0,
  92079. ],
  92080. ];
  92081. }
  92082. }
  92083. <?php
  92084. declare(strict_types=1);
  92085. namespace PhpCsFixer\RuleSet\Sets;
  92086. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  92087. use PhpCsFixer\RuleSet\DeprecatedRuleSetDescriptionInterface;
  92088. final class PERSet extends AbstractRuleSetDescription implements DeprecatedRuleSetDescriptionInterface
  92089. {
  92090. public function getRules(): array
  92091. {
  92092. return [
  92093. '@PER-CS' => true,
  92094. ];
  92095. }
  92096. public function getDescription(): string
  92097. {
  92098. return 'Alias for the newest PER-CS rules. It is recommended you use ``@PER-CS2.0`` instead if you want to stick with stable ruleset.';
  92099. }
  92100. public function getSuccessorsNames(): array
  92101. {
  92102. return ['@PER-CS'];
  92103. }
  92104. }
  92105. <?php
  92106. declare(strict_types=1);
  92107. namespace PhpCsFixer\RuleSet\Sets;
  92108. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  92109. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92110. final class PHPUnit55MigrationRiskySet extends AbstractMigrationSetDescription
  92111. {
  92112. public function getRules(): array
  92113. {
  92114. return [
  92115. '@PHPUnit54Migration:risky' => true,
  92116. 'php_unit_mock' => [
  92117. 'target' => PhpUnitTargetVersion::VERSION_5_5,
  92118. ],
  92119. ];
  92120. }
  92121. }
  92122. <?php
  92123. declare(strict_types=1);
  92124. namespace PhpCsFixer\RuleSet\Sets;
  92125. use PhpCsFixer\RuleSet\AbstractRuleSetDescription;
  92126. final class PERCS1x0RiskySet extends AbstractRuleSetDescription
  92127. {
  92128. public function getName(): string
  92129. {
  92130. return '@PER-CS1.0:risky';
  92131. }
  92132. public function getRules(): array
  92133. {
  92134. return [
  92135. '@PSR12:risky' => true,
  92136. ];
  92137. }
  92138. public function getDescription(): string
  92139. {
  92140. return 'Rules that follow `PER Coding Style 1.0 <https://www.php-fig.org/per/coding-style/>`_.';
  92141. }
  92142. }
  92143. <?php
  92144. declare(strict_types=1);
  92145. namespace PhpCsFixer\RuleSet\Sets;
  92146. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  92147. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92148. final class PHPUnit75MigrationRiskySet extends AbstractMigrationSetDescription
  92149. {
  92150. public function getRules(): array
  92151. {
  92152. return [
  92153. '@PHPUnit60Migration:risky' => true,
  92154. 'php_unit_dedicate_assert_internal_type' => [
  92155. 'target' => PhpUnitTargetVersion::VERSION_7_5,
  92156. ],
  92157. ];
  92158. }
  92159. }
  92160. <?php
  92161. declare(strict_types=1);
  92162. namespace PhpCsFixer\RuleSet\Sets;
  92163. use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  92164. use PhpCsFixer\RuleSet\AbstractMigrationSetDescription;
  92165. final class PHPUnit48MigrationRiskySet extends AbstractMigrationSetDescription
  92166. {
  92167. public function getRules(): array
  92168. {
  92169. return [
  92170. '@PHPUnit43Migration:risky' => true,
  92171. 'php_unit_namespaced' => [
  92172. 'target' => PhpUnitTargetVersion::VERSION_4_8,
  92173. ],
  92174. ];
  92175. }
  92176. }
  92177. <?php
  92178. declare(strict_types=1);
  92179. namespace PhpCsFixer\RuleSet;
  92180. abstract class AbstractRuleSetDescription implements RuleSetDescriptionInterface
  92181. {
  92182. public function __construct() {}
  92183. public function getName(): string
  92184. {
  92185. $name = substr(static::class, 1 + strrpos(static::class, '\\'), -3);
  92186. return '@'.str_replace('Risky', ':risky', $name);
  92187. }
  92188. public function isRisky(): bool
  92189. {
  92190. return str_contains(static::class, 'Risky');
  92191. }
  92192. }
  92193. <?php
  92194. declare(strict_types=1);
  92195. namespace PhpCsFixer\RuleSet;
  92196. use PhpCsFixer\Preg;
  92197. abstract class AbstractMigrationSetDescription extends AbstractRuleSetDescription
  92198. {
  92199. public function getDescription(): string
  92200. {
  92201. $name = $this->getName();
  92202. if (Preg::match('#^@PHPUnit(\d+)(\d)Migration.*$#', $name, $matches)) {
  92203. return \sprintf('Rules to improve tests code for PHPUnit %d.%d compatibility.', $matches[1], $matches[2]);
  92204. }
  92205. if (Preg::match('#^@PHP([\d]{2})Migration.*$#', $name, $matches)) {
  92206. return \sprintf('Rules to improve code for PHP %d.%d compatibility.', $matches[1][0], $matches[1][1]);
  92207. }
  92208. throw new \RuntimeException(\sprintf('Cannot generate description for "%s" "%s".', static::class, $name));
  92209. }
  92210. }
  92211. <?php
  92212. declare(strict_types=1);
  92213. namespace PhpCsFixer;
  92214. use PhpCsFixer\Tokenizer\Tokens;
  92215. abstract class AbstractNoUselessElseFixer extends AbstractFixer
  92216. {
  92217. public function getPriority(): int
  92218. {
  92219. return 39;
  92220. }
  92221. protected function isSuperfluousElse(Tokens $tokens, int $index): bool
  92222. {
  92223. $previousBlockStart = $index;
  92224. do {
  92225. [$previousBlockStart, $previousBlockEnd] = $this->getPreviousBlock($tokens, $previousBlockStart);
  92226. $previous = $previousBlockEnd;
  92227. if ($tokens[$previous]->equals('}')) {
  92228. $previous = $tokens->getPrevMeaningfulToken($previous);
  92229. }
  92230. if (
  92231. !$tokens[$previous]->equals(';')
  92232. || $tokens[$tokens->getPrevMeaningfulToken($previous)]->equals('{')
  92233. ) {
  92234. return false;
  92235. }
  92236. $candidateIndex = $tokens->getPrevTokenOfKind(
  92237. $previous,
  92238. [
  92239. ';',
  92240. [T_BREAK],
  92241. [T_CLOSE_TAG],
  92242. [T_CONTINUE],
  92243. [T_EXIT],
  92244. [T_GOTO],
  92245. [T_IF],
  92246. [T_RETURN],
  92247. [T_THROW],
  92248. ]
  92249. );
  92250. if (null === $candidateIndex || $tokens[$candidateIndex]->equalsAny([';', [T_CLOSE_TAG], [T_IF]])) {
  92251. return false;
  92252. }
  92253. if ($tokens[$candidateIndex]->isGivenKind(T_THROW)) {
  92254. $previousIndex = $tokens->getPrevMeaningfulToken($candidateIndex);
  92255. if (!$tokens[$previousIndex]->equalsAny([';', '{'])) {
  92256. return false;
  92257. }
  92258. }
  92259. if ($this->isInConditional($tokens, $candidateIndex, $previousBlockStart)
  92260. || $this->isInConditionWithoutBraces($tokens, $candidateIndex, $previousBlockStart)
  92261. ) {
  92262. return false;
  92263. }
  92264. } while (!$tokens[$previousBlockStart]->isGivenKind(T_IF));
  92265. return true;
  92266. }
  92267. private function getPreviousBlock(Tokens $tokens, int $index): array
  92268. {
  92269. $close = $previous = $tokens->getPrevMeaningfulToken($index);
  92270. if ($tokens[$close]->equals('}')) {
  92271. $previous = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $close);
  92272. }
  92273. $open = $tokens->getPrevTokenOfKind($previous, [[T_IF], [T_ELSE], [T_ELSEIF]]);
  92274. if ($tokens[$open]->isGivenKind(T_IF)) {
  92275. $elseCandidate = $tokens->getPrevMeaningfulToken($open);
  92276. if ($tokens[$elseCandidate]->isGivenKind(T_ELSE)) {
  92277. $open = $elseCandidate;
  92278. }
  92279. }
  92280. return [$open, $close];
  92281. }
  92282. private function isInConditional(Tokens $tokens, int $index, int $lowerLimitIndex): bool
  92283. {
  92284. $candidateIndex = $tokens->getPrevTokenOfKind($index, [')', ';', ':']);
  92285. if ($tokens[$candidateIndex]->equals(':')) {
  92286. return true;
  92287. }
  92288. if (!$tokens[$candidateIndex]->equals(')')) {
  92289. return false;
  92290. }
  92291. $open = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $candidateIndex);
  92292. return $tokens->getPrevMeaningfulToken($open) > $lowerLimitIndex;
  92293. }
  92294. private function isInConditionWithoutBraces(Tokens $tokens, int $index, int $lowerLimitIndex): bool
  92295. {
  92296. do {
  92297. if ($tokens[$index]->isComment() || $tokens[$index]->isWhitespace()) {
  92298. $index = $tokens->getPrevMeaningfulToken($index);
  92299. }
  92300. $token = $tokens[$index];
  92301. if ($token->isGivenKind([T_IF, T_ELSEIF, T_ELSE])) {
  92302. return true;
  92303. }
  92304. if ($token->equals(';')) {
  92305. return false;
  92306. }
  92307. if ($token->equals('{')) {
  92308. $index = $tokens->getPrevMeaningfulToken($index);
  92309. if ($tokens[$index]->isGivenKind(T_DO)) {
  92310. --$index;
  92311. continue;
  92312. }
  92313. if (!$tokens[$index]->equals(')')) {
  92314. return false;
  92315. }
  92316. $index = $tokens->findBlockStart(
  92317. Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
  92318. $index
  92319. );
  92320. $index = $tokens->getPrevMeaningfulToken($index);
  92321. if ($tokens[$index]->isGivenKind([T_IF, T_ELSEIF])) {
  92322. return false;
  92323. }
  92324. } elseif ($token->equals(')')) {
  92325. $type = Tokens::detectBlockType($token);
  92326. $index = $tokens->findBlockStart(
  92327. $type['type'],
  92328. $index
  92329. );
  92330. $index = $tokens->getPrevMeaningfulToken($index);
  92331. } else {
  92332. --$index;
  92333. }
  92334. } while ($index > $lowerLimitIndex);
  92335. return false;
  92336. }
  92337. }
  92338. <?php
  92339. declare(strict_types=1);
  92340. namespace PhpCsFixer\Cache;
  92341. use Symfony\Component\Filesystem\Exception\IOException;
  92342. final class FileHandler implements FileHandlerInterface
  92343. {
  92344. private \SplFileInfo $fileInfo;
  92345. private int $fileMTime = 0;
  92346. public function __construct(string $file)
  92347. {
  92348. $this->fileInfo = new \SplFileInfo($file);
  92349. }
  92350. public function getFile(): string
  92351. {
  92352. return $this->fileInfo->getPathname();
  92353. }
  92354. public function read(): ?CacheInterface
  92355. {
  92356. if (!$this->fileInfo->isFile() || !$this->fileInfo->isReadable()) {
  92357. return null;
  92358. }
  92359. $fileObject = $this->fileInfo->openFile('r');
  92360. $cache = $this->readFromHandle($fileObject);
  92361. $this->fileMTime = $this->getFileCurrentMTime();
  92362. unset($fileObject);
  92363. return $cache;
  92364. }
  92365. public function write(CacheInterface $cache): void
  92366. {
  92367. $this->ensureFileIsWriteable();
  92368. $fileObject = $this->fileInfo->openFile('r+');
  92369. if (method_exists($cache, 'backfillHashes') && $this->fileMTime < $this->getFileCurrentMTime()) {
  92370. $resultOfFlock = $fileObject->flock(LOCK_EX);
  92371. if (false === $resultOfFlock) {
  92372. }
  92373. $oldCache = $this->readFromHandle($fileObject);
  92374. $fileObject->rewind();
  92375. if (null !== $oldCache) {
  92376. $cache->backfillHashes($oldCache);
  92377. }
  92378. }
  92379. $resultOfTruncate = $fileObject->ftruncate(0);
  92380. if (false === $resultOfTruncate) {
  92381. return;
  92382. }
  92383. $resultOfWrite = $fileObject->fwrite($cache->toJson());
  92384. if (false === $resultOfWrite) {
  92385. return;
  92386. }
  92387. $resultOfFlush = $fileObject->fflush();
  92388. if (false === $resultOfFlush) {
  92389. }
  92390. $this->fileMTime = time();
  92391. }
  92392. private function getFileCurrentMTime(): int
  92393. {
  92394. clearstatcache(true, $this->fileInfo->getPathname());
  92395. $mtime = $this->fileInfo->getMTime();
  92396. if (false === $mtime) {
  92397. $mtime = 0;
  92398. }
  92399. return $mtime;
  92400. }
  92401. private function readFromHandle(\SplFileObject $fileObject): ?CacheInterface
  92402. {
  92403. try {
  92404. $size = $fileObject->getSize();
  92405. if (false === $size || 0 === $size) {
  92406. return null;
  92407. }
  92408. $content = $fileObject->fread($size);
  92409. if (false === $content) {
  92410. return null;
  92411. }
  92412. return Cache::fromJson($content);
  92413. } catch (\InvalidArgumentException $exception) {
  92414. return null;
  92415. }
  92416. }
  92417. private function ensureFileIsWriteable(): void
  92418. {
  92419. if ($this->fileInfo->isFile() && $this->fileInfo->isWritable()) {
  92420. return;
  92421. }
  92422. if ($this->fileInfo->isDir()) {
  92423. throw new IOException(
  92424. \sprintf('Cannot write cache file "%s" as the location exists as directory.', $this->fileInfo->getRealPath()),
  92425. 0,
  92426. null,
  92427. $this->fileInfo->getPathname()
  92428. );
  92429. }
  92430. if ($this->fileInfo->isFile() && !$this->fileInfo->isWritable()) {
  92431. throw new IOException(
  92432. \sprintf('Cannot write to file "%s" as it is not writable.', $this->fileInfo->getRealPath()),
  92433. 0,
  92434. null,
  92435. $this->fileInfo->getPathname()
  92436. );
  92437. }
  92438. $this->createFile($this->fileInfo->getPathname());
  92439. }
  92440. private function createFile(string $file): void
  92441. {
  92442. $dir = \dirname($file);
  92443. if (!@is_dir($dir)) {
  92444. @mkdir($dir, 0777, true);
  92445. }
  92446. if (!@is_dir($dir)) {
  92447. throw new IOException(
  92448. \sprintf('Directory of cache file "%s" does not exists and couldn\'t be created.', $file),
  92449. 0,
  92450. null,
  92451. $file
  92452. );
  92453. }
  92454. @touch($file);
  92455. @chmod($file, 0666);
  92456. }
  92457. }
  92458. <?php
  92459. declare(strict_types=1);
  92460. namespace PhpCsFixer\Cache;
  92461. use PhpCsFixer\Hasher;
  92462. final class FileCacheManager implements CacheManagerInterface
  92463. {
  92464. public const WRITE_FREQUENCY = 10;
  92465. private FileHandlerInterface $handler;
  92466. private SignatureInterface $signature;
  92467. private bool $isDryRun;
  92468. private DirectoryInterface $cacheDirectory;
  92469. private int $writeCounter = 0;
  92470. private bool $signatureWasUpdated = false;
  92471. private CacheInterface $cache;
  92472. public function __construct(
  92473. FileHandlerInterface $handler,
  92474. SignatureInterface $signature,
  92475. bool $isDryRun = false,
  92476. ?DirectoryInterface $cacheDirectory = null
  92477. ) {
  92478. $this->handler = $handler;
  92479. $this->signature = $signature;
  92480. $this->isDryRun = $isDryRun;
  92481. $this->cacheDirectory = $cacheDirectory ?? new Directory('');
  92482. $this->readCache();
  92483. }
  92484. public function __destruct()
  92485. {
  92486. if (true === $this->signatureWasUpdated || 0 !== $this->writeCounter) {
  92487. $this->writeCache();
  92488. }
  92489. }
  92490. public function __sleep(): array
  92491. {
  92492. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  92493. }
  92494. public function __wakeup(): void
  92495. {
  92496. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  92497. }
  92498. public function needFixing(string $file, string $fileContent): bool
  92499. {
  92500. $file = $this->cacheDirectory->getRelativePathTo($file);
  92501. return !$this->cache->has($file) || $this->cache->get($file) !== $this->calcHash($fileContent);
  92502. }
  92503. public function setFile(string $file, string $fileContent): void
  92504. {
  92505. $this->setFileHash($file, $this->calcHash($fileContent));
  92506. }
  92507. public function setFileHash(string $file, string $hash): void
  92508. {
  92509. $file = $this->cacheDirectory->getRelativePathTo($file);
  92510. if ($this->isDryRun && $this->cache->has($file) && $this->cache->get($file) !== $hash) {
  92511. $this->cache->clear($file);
  92512. } else {
  92513. $this->cache->set($file, $hash);
  92514. }
  92515. if (self::WRITE_FREQUENCY === ++$this->writeCounter) {
  92516. $this->writeCounter = 0;
  92517. $this->writeCache();
  92518. }
  92519. }
  92520. private function readCache(): void
  92521. {
  92522. $cache = $this->handler->read();
  92523. if (null === $cache || !$this->signature->equals($cache->getSignature())) {
  92524. $cache = new Cache($this->signature);
  92525. $this->signatureWasUpdated = true;
  92526. }
  92527. $this->cache = $cache;
  92528. }
  92529. private function writeCache(): void
  92530. {
  92531. $this->handler->write($this->cache);
  92532. }
  92533. private function calcHash(string $content): string
  92534. {
  92535. return Hasher::calculate($content);
  92536. }
  92537. }
  92538. <?php
  92539. declare(strict_types=1);
  92540. namespace PhpCsFixer\Cache;
  92541. use PhpCsFixer\Utils;
  92542. final class Cache implements CacheInterface
  92543. {
  92544. private SignatureInterface $signature;
  92545. private array $hashes = [];
  92546. public function __construct(SignatureInterface $signature)
  92547. {
  92548. $this->signature = $signature;
  92549. }
  92550. public function getSignature(): SignatureInterface
  92551. {
  92552. return $this->signature;
  92553. }
  92554. public function has(string $file): bool
  92555. {
  92556. return \array_key_exists($file, $this->hashes);
  92557. }
  92558. public function get(string $file): ?string
  92559. {
  92560. if (!$this->has($file)) {
  92561. return null;
  92562. }
  92563. return $this->hashes[$file];
  92564. }
  92565. public function set(string $file, string $hash): void
  92566. {
  92567. $this->hashes[$file] = $hash;
  92568. }
  92569. public function clear(string $file): void
  92570. {
  92571. unset($this->hashes[$file]);
  92572. }
  92573. public function toJson(): string
  92574. {
  92575. $json = json_encode([
  92576. 'php' => $this->getSignature()->getPhpVersion(),
  92577. 'version' => $this->getSignature()->getFixerVersion(),
  92578. 'indent' => $this->getSignature()->getIndent(),
  92579. 'lineEnding' => $this->getSignature()->getLineEnding(),
  92580. 'rules' => $this->getSignature()->getRules(),
  92581. 'hashes' => $this->hashes,
  92582. ]);
  92583. if (JSON_ERROR_NONE !== json_last_error() || false === $json) {
  92584. throw new \UnexpectedValueException(\sprintf(
  92585. 'Cannot encode cache signature to JSON, error: "%s". If you have non-UTF8 chars in your signature, like in license for `header_comment`, consider enabling `ext-mbstring` or install `symfony/polyfill-mbstring`.',
  92586. json_last_error_msg()
  92587. ));
  92588. }
  92589. return $json;
  92590. }
  92591. public static function fromJson(string $json): self
  92592. {
  92593. $data = json_decode($json, true);
  92594. if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
  92595. throw new \InvalidArgumentException(\sprintf(
  92596. 'Value needs to be a valid JSON string, got "%s", error: "%s".',
  92597. $json,
  92598. json_last_error_msg()
  92599. ));
  92600. }
  92601. $requiredKeys = [
  92602. 'php',
  92603. 'version',
  92604. 'indent',
  92605. 'lineEnding',
  92606. 'rules',
  92607. 'hashes',
  92608. ];
  92609. $missingKeys = array_diff_key(array_flip($requiredKeys), $data);
  92610. if (\count($missingKeys) > 0) {
  92611. throw new \InvalidArgumentException(\sprintf(
  92612. 'JSON data is missing keys %s',
  92613. Utils::naturalLanguageJoin(array_keys($missingKeys))
  92614. ));
  92615. }
  92616. $signature = new Signature(
  92617. $data['php'],
  92618. $data['version'],
  92619. $data['indent'],
  92620. $data['lineEnding'],
  92621. $data['rules']
  92622. );
  92623. $cache = new self($signature);
  92624. $cache->hashes = array_map(static fn ($v): string => \is_int($v) ? (string) $v : $v, $data['hashes']);
  92625. return $cache;
  92626. }
  92627. public function backfillHashes(self $oldCache): bool
  92628. {
  92629. if (!$this->getSignature()->equals($oldCache->getSignature())) {
  92630. return false;
  92631. }
  92632. $this->hashes = array_merge($oldCache->hashes, $this->hashes);
  92633. return true;
  92634. }
  92635. }
  92636. <?php
  92637. declare(strict_types=1);
  92638. namespace PhpCsFixer\Cache;
  92639. interface CacheInterface
  92640. {
  92641. public function getSignature(): SignatureInterface;
  92642. public function has(string $file): bool;
  92643. public function get(string $file): ?string;
  92644. public function set(string $file, string $hash): void;
  92645. public function clear(string $file): void;
  92646. public function toJson(): string;
  92647. }
  92648. <?php
  92649. declare(strict_types=1);
  92650. namespace PhpCsFixer\Cache;
  92651. final class NullCacheManager implements CacheManagerInterface
  92652. {
  92653. public function needFixing(string $file, string $fileContent): bool
  92654. {
  92655. return true;
  92656. }
  92657. public function setFile(string $file, string $fileContent): void {}
  92658. public function setFileHash(string $file, string $hash): void {}
  92659. }
  92660. <?php
  92661. declare(strict_types=1);
  92662. namespace PhpCsFixer\Cache;
  92663. interface CacheManagerInterface
  92664. {
  92665. public function needFixing(string $file, string $fileContent): bool;
  92666. public function setFile(string $file, string $fileContent): void;
  92667. public function setFileHash(string $file, string $hash): void;
  92668. }
  92669. <?php
  92670. declare(strict_types=1);
  92671. namespace PhpCsFixer\Cache;
  92672. interface FileHandlerInterface
  92673. {
  92674. public function getFile(): string;
  92675. public function read(): ?CacheInterface;
  92676. public function write(CacheInterface $cache): void;
  92677. }
  92678. <?php
  92679. declare(strict_types=1);
  92680. namespace PhpCsFixer\Cache;
  92681. /**
  92682. @readonly
  92683. */
  92684. final class Directory implements DirectoryInterface
  92685. {
  92686. private string $directoryName;
  92687. public function __construct(string $directoryName)
  92688. {
  92689. $this->directoryName = $directoryName;
  92690. }
  92691. public function getRelativePathTo(string $file): string
  92692. {
  92693. $file = $this->normalizePath($file);
  92694. if (
  92695. '' === $this->directoryName
  92696. || 0 !== stripos($file, $this->directoryName.\DIRECTORY_SEPARATOR)
  92697. ) {
  92698. return $file;
  92699. }
  92700. return substr($file, \strlen($this->directoryName) + 1);
  92701. }
  92702. private function normalizePath(string $path): string
  92703. {
  92704. return str_replace(['\\', '/'], \DIRECTORY_SEPARATOR, $path);
  92705. }
  92706. }
  92707. <?php
  92708. declare(strict_types=1);
  92709. namespace PhpCsFixer\Cache;
  92710. interface SignatureInterface
  92711. {
  92712. public function getPhpVersion(): string;
  92713. public function getFixerVersion(): string;
  92714. public function getIndent(): string;
  92715. public function getLineEnding(): string;
  92716. public function getRules(): array;
  92717. public function equals(self $signature): bool;
  92718. }
  92719. <?php
  92720. declare(strict_types=1);
  92721. namespace PhpCsFixer\Cache;
  92722. interface DirectoryInterface
  92723. {
  92724. public function getRelativePathTo(string $file): string;
  92725. }
  92726. <?php
  92727. declare(strict_types=1);
  92728. namespace PhpCsFixer\Cache;
  92729. /**
  92730. @readonly
  92731. */
  92732. final class Signature implements SignatureInterface
  92733. {
  92734. private string $phpVersion;
  92735. private string $fixerVersion;
  92736. private string $indent;
  92737. private string $lineEnding;
  92738. private array $rules;
  92739. public function __construct(string $phpVersion, string $fixerVersion, string $indent, string $lineEnding, array $rules)
  92740. {
  92741. $this->phpVersion = $phpVersion;
  92742. $this->fixerVersion = $fixerVersion;
  92743. $this->indent = $indent;
  92744. $this->lineEnding = $lineEnding;
  92745. $this->rules = self::makeJsonEncodable($rules);
  92746. }
  92747. public function getPhpVersion(): string
  92748. {
  92749. return $this->phpVersion;
  92750. }
  92751. public function getFixerVersion(): string
  92752. {
  92753. return $this->fixerVersion;
  92754. }
  92755. public function getIndent(): string
  92756. {
  92757. return $this->indent;
  92758. }
  92759. public function getLineEnding(): string
  92760. {
  92761. return $this->lineEnding;
  92762. }
  92763. public function getRules(): array
  92764. {
  92765. return $this->rules;
  92766. }
  92767. public function equals(SignatureInterface $signature): bool
  92768. {
  92769. return $this->phpVersion === $signature->getPhpVersion()
  92770. && $this->fixerVersion === $signature->getFixerVersion()
  92771. && $this->indent === $signature->getIndent()
  92772. && $this->lineEnding === $signature->getLineEnding()
  92773. && $this->rules === $signature->getRules();
  92774. }
  92775. private static function makeJsonEncodable(array $data): array
  92776. {
  92777. array_walk_recursive($data, static function (&$item): void {
  92778. if (\is_string($item) && !mb_detect_encoding($item, 'utf-8', true)) {
  92779. $item = base64_encode($item);
  92780. }
  92781. });
  92782. return $data;
  92783. }
  92784. }
  92785. <?php
  92786. declare(strict_types=1);
  92787. namespace PhpCsFixer\Linter;
  92788. use Symfony\Component\Process\Process;
  92789. final class ProcessLintingResult implements LintingResultInterface
  92790. {
  92791. private Process $process;
  92792. private ?string $path;
  92793. private ?bool $isSuccessful = null;
  92794. public function __construct(Process $process, ?string $path = null)
  92795. {
  92796. $this->process = $process;
  92797. $this->path = $path;
  92798. }
  92799. public function check(): void
  92800. {
  92801. if (!$this->isSuccessful()) {
  92802. throw new LintingException($this->getProcessErrorMessage(), $this->process->getExitCode());
  92803. }
  92804. }
  92805. private function getProcessErrorMessage(): string
  92806. {
  92807. $errorOutput = $this->process->getErrorOutput();
  92808. $output = strtok(ltrim('' !== $errorOutput ? $errorOutput : $this->process->getOutput()), "\n");
  92809. if (false === $output) {
  92810. return 'Fatal error: Unable to lint file.';
  92811. }
  92812. if (null !== $this->path) {
  92813. $needle = \sprintf('in %s ', $this->path);
  92814. $pos = strrpos($output, $needle);
  92815. if (false !== $pos) {
  92816. $output = \sprintf('%s%s', substr($output, 0, $pos), substr($output, $pos + \strlen($needle)));
  92817. }
  92818. }
  92819. $prefix = substr($output, 0, 18);
  92820. if ('PHP Parse error: ' === $prefix) {
  92821. return \sprintf('Parse error: %s.', substr($output, 18));
  92822. }
  92823. if ('PHP Fatal error: ' === $prefix) {
  92824. return \sprintf('Fatal error: %s.', substr($output, 18));
  92825. }
  92826. return \sprintf('%s.', $output);
  92827. }
  92828. private function isSuccessful(): bool
  92829. {
  92830. if (null === $this->isSuccessful) {
  92831. $this->process->wait();
  92832. $this->isSuccessful = $this->process->isSuccessful();
  92833. }
  92834. return $this->isSuccessful;
  92835. }
  92836. }
  92837. <?php
  92838. declare(strict_types=1);
  92839. namespace PhpCsFixer\Linter;
  92840. interface LintingResultInterface
  92841. {
  92842. public function check(): void;
  92843. }
  92844. <?php
  92845. declare(strict_types=1);
  92846. namespace PhpCsFixer\Linter;
  92847. use PhpCsFixer\FileReader;
  92848. use PhpCsFixer\FileRemoval;
  92849. use Symfony\Component\Filesystem\Exception\IOException;
  92850. use Symfony\Component\Process\PhpExecutableFinder;
  92851. use Symfony\Component\Process\Process;
  92852. final class ProcessLinter implements LinterInterface
  92853. {
  92854. private FileRemoval $fileRemoval;
  92855. private ProcessLinterProcessBuilder $processBuilder;
  92856. private ?string $temporaryFile = null;
  92857. public function __construct(?string $executable = null)
  92858. {
  92859. if (null === $executable) {
  92860. $executableFinder = new PhpExecutableFinder();
  92861. $executable = $executableFinder->find(false);
  92862. if (false === $executable) {
  92863. throw new UnavailableLinterException('Cannot find PHP executable.');
  92864. }
  92865. if ('phpdbg' === \PHP_SAPI) {
  92866. if (!str_contains($executable, 'phpdbg')) {
  92867. throw new UnavailableLinterException('Automatically found PHP executable is non-standard phpdbg. Could not find proper PHP executable.');
  92868. }
  92869. $executable = str_replace('phpdbg', 'php', $executable);
  92870. if (!is_executable($executable)) {
  92871. throw new UnavailableLinterException('Automatically found PHP executable is phpdbg. Could not find proper PHP executable.');
  92872. }
  92873. }
  92874. }
  92875. $this->processBuilder = new ProcessLinterProcessBuilder($executable);
  92876. $this->fileRemoval = new FileRemoval();
  92877. }
  92878. public function __destruct()
  92879. {
  92880. if (null !== $this->temporaryFile) {
  92881. $this->fileRemoval->delete($this->temporaryFile);
  92882. }
  92883. }
  92884. public function __sleep(): array
  92885. {
  92886. throw new \BadMethodCallException('Cannot serialize '.self::class);
  92887. }
  92888. public function __wakeup(): void
  92889. {
  92890. throw new \BadMethodCallException('Cannot unserialize '.self::class);
  92891. }
  92892. public function isAsync(): bool
  92893. {
  92894. return true;
  92895. }
  92896. public function lintFile(string $path): LintingResultInterface
  92897. {
  92898. return new ProcessLintingResult($this->createProcessForFile($path), $path);
  92899. }
  92900. public function lintSource(string $source): LintingResultInterface
  92901. {
  92902. return new ProcessLintingResult($this->createProcessForSource($source), $this->temporaryFile);
  92903. }
  92904. private function createProcessForFile(string $path): Process
  92905. {
  92906. if (!is_file($path)) {
  92907. return $this->createProcessForSource(FileReader::createSingleton()->read($path));
  92908. }
  92909. $process = $this->processBuilder->build($path);
  92910. $process->setTimeout(10);
  92911. $process->start();
  92912. return $process;
  92913. }
  92914. private function createProcessForSource(string $source): Process
  92915. {
  92916. if (null === $this->temporaryFile) {
  92917. $this->temporaryFile = tempnam(sys_get_temp_dir(), 'cs_fixer_tmp_');
  92918. $this->fileRemoval->observe($this->temporaryFile);
  92919. }
  92920. if (false === @file_put_contents($this->temporaryFile, $source)) {
  92921. throw new IOException(\sprintf('Failed to write file "%s".', $this->temporaryFile), 0, null, $this->temporaryFile);
  92922. }
  92923. return $this->createProcessForFile($this->temporaryFile);
  92924. }
  92925. }
  92926. <?php
  92927. declare(strict_types=1);
  92928. namespace PhpCsFixer\Linter;
  92929. /**
  92930. @readonly
  92931. */
  92932. final class TokenizerLintingResult implements LintingResultInterface
  92933. {
  92934. private ?\Error $error;
  92935. public function __construct(?\Error $error = null)
  92936. {
  92937. $this->error = $error;
  92938. }
  92939. public function check(): void
  92940. {
  92941. if (null !== $this->error) {
  92942. throw new LintingException(
  92943. \sprintf('%s: %s on line %d.', $this->getMessagePrefix(), $this->error->getMessage(), $this->error->getLine()),
  92944. $this->error->getCode(),
  92945. $this->error
  92946. );
  92947. }
  92948. }
  92949. private function getMessagePrefix(): string
  92950. {
  92951. return $this->error instanceof \ParseError ? 'Parse error' : 'Fatal error';
  92952. }
  92953. }
  92954. <?php
  92955. declare(strict_types=1);
  92956. namespace PhpCsFixer\Linter;
  92957. class UnavailableLinterException extends \RuntimeException {}
  92958. <?php
  92959. declare(strict_types=1);
  92960. namespace PhpCsFixer\Linter;
  92961. class LintingException extends \RuntimeException {}
  92962. <?php
  92963. declare(strict_types=1);
  92964. namespace PhpCsFixer\Linter;
  92965. use Symfony\Component\Process\Process;
  92966. /**
  92967. @readonly
  92968. */
  92969. final class ProcessLinterProcessBuilder
  92970. {
  92971. private string $executable;
  92972. public function __construct(string $executable)
  92973. {
  92974. $this->executable = $executable;
  92975. }
  92976. public function build(string $path): Process
  92977. {
  92978. return new Process([
  92979. $this->executable,
  92980. '-l',
  92981. $path,
  92982. ]);
  92983. }
  92984. }
  92985. <?php
  92986. declare(strict_types=1);
  92987. namespace PhpCsFixer\Linter;
  92988. interface LinterInterface
  92989. {
  92990. public function isAsync(): bool;
  92991. public function lintFile(string $path): LintingResultInterface;
  92992. public function lintSource(string $source): LintingResultInterface;
  92993. }
  92994. <?php
  92995. declare(strict_types=1);
  92996. namespace PhpCsFixer\Linter;
  92997. /**
  92998. @readonly
  92999. */
  93000. final class Linter implements LinterInterface
  93001. {
  93002. private LinterInterface $subLinter;
  93003. public function __construct()
  93004. {
  93005. $this->subLinter = new TokenizerLinter();
  93006. }
  93007. public function isAsync(): bool
  93008. {
  93009. return $this->subLinter->isAsync();
  93010. }
  93011. public function lintFile(string $path): LintingResultInterface
  93012. {
  93013. return $this->subLinter->lintFile($path);
  93014. }
  93015. public function lintSource(string $source): LintingResultInterface
  93016. {
  93017. return $this->subLinter->lintSource($source);
  93018. }
  93019. }
  93020. <?php
  93021. declare(strict_types=1);
  93022. namespace PhpCsFixer\Linter;
  93023. use PhpCsFixer\FileReader;
  93024. use PhpCsFixer\Hasher;
  93025. use PhpCsFixer\Tokenizer\Tokens;
  93026. /**
  93027. @readonly
  93028. */
  93029. final class TokenizerLinter implements LinterInterface
  93030. {
  93031. public function isAsync(): bool
  93032. {
  93033. return false;
  93034. }
  93035. public function lintFile(string $path): LintingResultInterface
  93036. {
  93037. return $this->lintSource(FileReader::createSingleton()->read($path));
  93038. }
  93039. public function lintSource(string $source): LintingResultInterface
  93040. {
  93041. try {
  93042. $codeHash = Hasher::calculate($source);
  93043. Tokens::clearCache($codeHash);
  93044. Tokens::fromCode($source);
  93045. return new TokenizerLintingResult();
  93046. } catch (\CompileError|\ParseError $e) {
  93047. return new TokenizerLintingResult($e);
  93048. }
  93049. }
  93050. }
  93051. <?php
  93052. declare(strict_types=1);
  93053. namespace PhpCsFixer\Linter;
  93054. use PhpCsFixer\Hasher;
  93055. final class CachingLinter implements LinterInterface
  93056. {
  93057. private LinterInterface $sublinter;
  93058. private array $cache = [];
  93059. public function __construct(LinterInterface $linter)
  93060. {
  93061. $this->sublinter = $linter;
  93062. }
  93063. public function isAsync(): bool
  93064. {
  93065. return $this->sublinter->isAsync();
  93066. }
  93067. public function lintFile(string $path): LintingResultInterface
  93068. {
  93069. $checksum = Hasher::calculate(file_get_contents($path));
  93070. return $this->cache[$checksum] ??= $this->sublinter->lintFile($path);
  93071. }
  93072. public function lintSource(string $source): LintingResultInterface
  93073. {
  93074. $checksum = Hasher::calculate($source);
  93075. return $this->cache[$checksum] ??= $this->sublinter->lintSource($source);
  93076. }
  93077. }
  93078. <?php
  93079. declare(strict_types=1);
  93080. namespace PhpCsFixer;
  93081. final class PregException extends \RuntimeException {}
  93082. <?php
  93083. declare(strict_types=1);
  93084. namespace PhpCsFixer;
  93085. use PhpCsFixer\Fixer\FixerInterface;
  93086. interface ConfigInterface
  93087. {
  93088. public const PHP_VERSION_SYNTAX_SUPPORTED = '8.4';
  93089. public function getCacheFile(): ?string;
  93090. public function getCustomFixers(): array;
  93091. public function getFinder(): iterable;
  93092. public function getFormat(): string;
  93093. public function getHideProgress(): bool;
  93094. public function getIndent(): string;
  93095. public function getLineEnding(): string;
  93096. public function getName(): string;
  93097. public function getPhpExecutable(): ?string;
  93098. public function getRiskyAllowed(): bool;
  93099. public function getRules(): array;
  93100. public function getUsingCache(): bool;
  93101. public function registerCustomFixers(iterable $fixers): self;
  93102. public function setCacheFile(string $cacheFile): self;
  93103. public function setFinder(iterable $finder): self;
  93104. public function setFormat(string $format): self;
  93105. public function setHideProgress(bool $hideProgress): self;
  93106. public function setIndent(string $indent): self;
  93107. public function setLineEnding(string $lineEnding): self;
  93108. public function setPhpExecutable(?string $phpExecutable): self;
  93109. public function setRiskyAllowed(bool $isRiskyAllowed): self;
  93110. public function setRules(array $rules): self;
  93111. public function setUsingCache(bool $usingCache): self;
  93112. }
  93113. <?php
  93114. declare(strict_types=1);
  93115. namespace PhpCsFixer;
  93116. final class FileReader
  93117. {
  93118. private ?string $stdinContent = null;
  93119. public static function createSingleton(): self
  93120. {
  93121. static $instance = null;
  93122. if (!$instance) {
  93123. $instance = new self();
  93124. }
  93125. return $instance;
  93126. }
  93127. public function read(string $filePath): string
  93128. {
  93129. if ('php://stdin' === $filePath) {
  93130. if (null === $this->stdinContent) {
  93131. $this->stdinContent = $this->readRaw($filePath);
  93132. }
  93133. return $this->stdinContent;
  93134. }
  93135. return $this->readRaw($filePath);
  93136. }
  93137. private function readRaw(string $realPath): string
  93138. {
  93139. $content = @file_get_contents($realPath);
  93140. if (false === $content) {
  93141. $error = error_get_last();
  93142. throw new \RuntimeException(\sprintf(
  93143. 'Failed to read content from "%s".%s',
  93144. $realPath,
  93145. null !== $error ? ' '.$error['message'] : ''
  93146. ));
  93147. }
  93148. return $content;
  93149. }
  93150. }
  93151. <?php
  93152. declare(strict_types=1);
  93153. namespace PhpCsFixer;
  93154. use PhpCsFixer\DocBlock\Annotation;
  93155. use PhpCsFixer\DocBlock\DocBlock;
  93156. use PhpCsFixer\DocBlock\TypeExpression;
  93157. use PhpCsFixer\Tokenizer\Token;
  93158. use PhpCsFixer\Tokenizer\Tokens;
  93159. abstract class AbstractPhpdocTypesFixer extends AbstractFixer
  93160. {
  93161. protected array $tags;
  93162. public function __construct()
  93163. {
  93164. parent::__construct();
  93165. $this->tags = Annotation::getTagsWithTypes();
  93166. }
  93167. public function isCandidate(Tokens $tokens): bool
  93168. {
  93169. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  93170. }
  93171. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  93172. {
  93173. foreach ($tokens as $index => $token) {
  93174. if (!$token->isGivenKind(T_DOC_COMMENT)) {
  93175. continue;
  93176. }
  93177. $doc = new DocBlock($token->getContent());
  93178. $annotations = $doc->getAnnotationsOfType($this->tags);
  93179. if (0 === \count($annotations)) {
  93180. continue;
  93181. }
  93182. foreach ($annotations as $annotation) {
  93183. $this->fixType($annotation);
  93184. }
  93185. $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
  93186. }
  93187. }
  93188. abstract protected function normalize(string $type): string;
  93189. private function fixType(Annotation $annotation): void
  93190. {
  93191. $typeExpression = $annotation->getTypeExpression();
  93192. if (null === $typeExpression) {
  93193. return;
  93194. }
  93195. $newTypeExpression = $typeExpression->mapTypes(function (TypeExpression $type) {
  93196. if (!$type->isCompositeType()) {
  93197. $value = $this->normalize($type->toString());
  93198. return new TypeExpression($value, null, []);
  93199. }
  93200. return $type;
  93201. });
  93202. $annotation->setTypes([$newTypeExpression->toString()]);
  93203. }
  93204. }
  93205. <?php
  93206. declare(strict_types=1);
  93207. namespace PhpCsFixer\Tokenizer;
  93208. use PhpCsFixer\Tokenizer\Analyzer\AttributeAnalyzer;
  93209. use PhpCsFixer\Tokenizer\Analyzer\GotoLabelAnalyzer;
  93210. /**
  93211. @phpstan-type
  93212. */
  93213. final class TokensAnalyzer
  93214. {
  93215. private Tokens $tokens;
  93216. /**
  93217. @readonly
  93218. */
  93219. private GotoLabelAnalyzer $gotoLabelAnalyzer;
  93220. public function __construct(Tokens $tokens)
  93221. {
  93222. $this->tokens = $tokens;
  93223. $this->gotoLabelAnalyzer = new GotoLabelAnalyzer();
  93224. }
  93225. public function getClassyElements(): array
  93226. {
  93227. $elements = [];
  93228. for ($index = 1, $count = \count($this->tokens) - 2; $index < $count; ++$index) {
  93229. if ($this->tokens[$index]->isClassy()) {
  93230. [$index, $newElements] = $this->findClassyElements($index, $index);
  93231. $elements += $newElements;
  93232. }
  93233. }
  93234. ksort($elements);
  93235. return $elements;
  93236. }
  93237. public function getClassyModifiers(int $index): array
  93238. {
  93239. if (!$this->tokens[$index]->isClassy()) {
  93240. throw new \InvalidArgumentException(\sprintf('Not an "classy" at given index %d.', $index));
  93241. }
  93242. $modifiers = ['final' => null, 'abstract' => null, 'readonly' => null];
  93243. while (true) {
  93244. $index = $this->tokens->getPrevMeaningfulToken($index);
  93245. if ($this->tokens[$index]->isGivenKind(T_FINAL)) {
  93246. $modifiers['final'] = $index;
  93247. } elseif ($this->tokens[$index]->isGivenKind(T_ABSTRACT)) {
  93248. $modifiers['abstract'] = $index;
  93249. } elseif ($this->tokens[$index]->isGivenKind(FCT::T_READONLY)) {
  93250. $modifiers['readonly'] = $index;
  93251. } else {
  93252. break;
  93253. }
  93254. }
  93255. return $modifiers;
  93256. }
  93257. public function getImportUseIndexes(bool $perNamespace = false): array
  93258. {
  93259. $tokens = $this->tokens;
  93260. $uses = [];
  93261. $namespaceIndex = 0;
  93262. for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
  93263. $token = $tokens[$index];
  93264. if ($token->isGivenKind(T_NAMESPACE)) {
  93265. $nextTokenIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  93266. $nextToken = $tokens[$nextTokenIndex];
  93267. if ($nextToken->equals('{')) {
  93268. $index = $nextTokenIndex;
  93269. }
  93270. if ($perNamespace) {
  93271. ++$namespaceIndex;
  93272. }
  93273. continue;
  93274. }
  93275. if ($token->isGivenKind(T_USE)) {
  93276. $uses[$namespaceIndex][] = $index;
  93277. }
  93278. }
  93279. if (!$perNamespace && isset($uses[$namespaceIndex])) {
  93280. return $uses[$namespaceIndex];
  93281. }
  93282. return $uses;
  93283. }
  93284. public function isArray(int $index): bool
  93285. {
  93286. return $this->tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
  93287. }
  93288. public function isArrayMultiLine(int $index): bool
  93289. {
  93290. if (!$this->isArray($index)) {
  93291. throw new \InvalidArgumentException(\sprintf('Not an array at given index %d.', $index));
  93292. }
  93293. $tokens = $this->tokens;
  93294. if ($tokens[$index]->isGivenKind(T_ARRAY)) {
  93295. $index = $tokens->getNextMeaningfulToken($index);
  93296. }
  93297. return $this->isBlockMultiline($tokens, $index);
  93298. }
  93299. public function isBlockMultiline(Tokens $tokens, int $index): bool
  93300. {
  93301. $blockType = Tokens::detectBlockType($tokens[$index]);
  93302. if (null === $blockType || !$blockType['isStart']) {
  93303. throw new \InvalidArgumentException(\sprintf('Not an block start at given index %d.', $index));
  93304. }
  93305. $endIndex = $tokens->findBlockEnd($blockType['type'], $index);
  93306. for (++$index; $index < $endIndex; ++$index) {
  93307. $token = $tokens[$index];
  93308. $blockType = Tokens::detectBlockType($token);
  93309. if (null !== $blockType && $blockType['isStart']) {
  93310. $index = $tokens->findBlockEnd($blockType['type'], $index);
  93311. continue;
  93312. }
  93313. if (
  93314. $token->isWhitespace()
  93315. && !$tokens[$index - 1]->isGivenKind(T_END_HEREDOC)
  93316. && str_contains($token->getContent(), "\n")
  93317. ) {
  93318. return true;
  93319. }
  93320. }
  93321. return false;
  93322. }
  93323. public function getMethodAttributes(int $index): array
  93324. {
  93325. if (!$this->tokens[$index]->isGivenKind(T_FUNCTION)) {
  93326. throw new \LogicException(\sprintf('No T_FUNCTION at given index %d, got "%s".', $index, $this->tokens[$index]->getName()));
  93327. }
  93328. $attributes = [
  93329. 'visibility' => null,
  93330. 'static' => false,
  93331. 'abstract' => false,
  93332. 'final' => false,
  93333. ];
  93334. for ($i = $index; $i >= 0; --$i) {
  93335. $i = $this->tokens->getPrevMeaningfulToken($i);
  93336. $token = $this->tokens[$i];
  93337. if ($token->isGivenKind(T_STATIC)) {
  93338. $attributes['static'] = true;
  93339. continue;
  93340. }
  93341. if ($token->isGivenKind(T_FINAL)) {
  93342. $attributes['final'] = true;
  93343. continue;
  93344. }
  93345. if ($token->isGivenKind(T_ABSTRACT)) {
  93346. $attributes['abstract'] = true;
  93347. continue;
  93348. }
  93349. if ($token->isGivenKind(T_PRIVATE)) {
  93350. $attributes['visibility'] = T_PRIVATE;
  93351. continue;
  93352. }
  93353. if ($token->isGivenKind(T_PROTECTED)) {
  93354. $attributes['visibility'] = T_PROTECTED;
  93355. continue;
  93356. }
  93357. if ($token->isGivenKind(T_PUBLIC)) {
  93358. $attributes['visibility'] = T_PUBLIC;
  93359. continue;
  93360. }
  93361. break;
  93362. }
  93363. return $attributes;
  93364. }
  93365. public function isAnonymousClass(int $index): bool
  93366. {
  93367. if (!$this->tokens[$index]->isClassy()) {
  93368. throw new \LogicException(\sprintf('No classy token at given index %d.', $index));
  93369. }
  93370. if (!$this->tokens[$index]->isGivenKind(T_CLASS)) {
  93371. return false;
  93372. }
  93373. $index = $this->tokens->getPrevMeaningfulToken($index);
  93374. if ($this->tokens[$index]->isGivenKind(FCT::T_READONLY)) {
  93375. $index = $this->tokens->getPrevMeaningfulToken($index);
  93376. }
  93377. while ($this->tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  93378. $index = $this->tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  93379. $index = $this->tokens->getPrevMeaningfulToken($index);
  93380. }
  93381. return $this->tokens[$index]->isGivenKind(T_NEW);
  93382. }
  93383. public function isLambda(int $index): bool
  93384. {
  93385. if (!$this->tokens[$index]->isGivenKind([T_FUNCTION, T_FN])) {
  93386. throw new \LogicException(\sprintf('No T_FUNCTION or T_FN at given index %d, got "%s".', $index, $this->tokens[$index]->getName()));
  93387. }
  93388. $startParenthesisIndex = $this->tokens->getNextMeaningfulToken($index);
  93389. $startParenthesisToken = $this->tokens[$startParenthesisIndex];
  93390. if ($startParenthesisToken->isGivenKind(CT::T_RETURN_REF)) {
  93391. $startParenthesisIndex = $this->tokens->getNextMeaningfulToken($startParenthesisIndex);
  93392. $startParenthesisToken = $this->tokens[$startParenthesisIndex];
  93393. }
  93394. return $startParenthesisToken->equals('(');
  93395. }
  93396. public function getLastTokenIndexOfArrowFunction(int $index): int
  93397. {
  93398. if (!$this->tokens[$index]->isGivenKind(T_FN)) {
  93399. throw new \InvalidArgumentException(\sprintf('Not an "arrow function" at given index %d.', $index));
  93400. }
  93401. $stopTokens = [')', ']', ',', ';', [T_CLOSE_TAG]];
  93402. $index = $this->tokens->getNextTokenOfKind($index, [[T_DOUBLE_ARROW]]);
  93403. while (true) {
  93404. $index = $this->tokens->getNextMeaningfulToken($index);
  93405. if ($this->tokens[$index]->equalsAny($stopTokens)) {
  93406. break;
  93407. }
  93408. $blockType = Tokens::detectBlockType($this->tokens[$index]);
  93409. if (null === $blockType) {
  93410. continue;
  93411. }
  93412. if ($blockType['isStart']) {
  93413. $index = $this->tokens->findBlockEnd($blockType['type'], $index);
  93414. continue;
  93415. }
  93416. break;
  93417. }
  93418. return $this->tokens->getPrevMeaningfulToken($index);
  93419. }
  93420. public function isConstantInvocation(int $index): bool
  93421. {
  93422. if (!$this->tokens[$index]->isGivenKind(T_STRING)) {
  93423. throw new \LogicException(\sprintf('No T_STRING at given index %d, got "%s".', $index, $this->tokens[$index]->getName()));
  93424. }
  93425. $nextIndex = $this->tokens->getNextMeaningfulToken($index);
  93426. if (
  93427. $this->tokens[$nextIndex]->equalsAny(['(', '{'])
  93428. || $this->tokens[$nextIndex]->isGivenKind([T_DOUBLE_COLON, T_ELLIPSIS, T_NS_SEPARATOR, CT::T_RETURN_REF, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, T_VARIABLE])
  93429. ) {
  93430. return false;
  93431. }
  93432. if ($this->tokens[$nextIndex]->isGivenKind(T_AS)) {
  93433. $prevIndex = $this->tokens->getPrevMeaningfulToken($index);
  93434. if (!$this->tokens[$prevIndex]->equals('(')) {
  93435. return false;
  93436. }
  93437. }
  93438. $prevIndex = $this->tokens->getPrevMeaningfulToken($index);
  93439. if ($this->tokens[$prevIndex]->isGivenKind(Token::getClassyTokenKinds())) {
  93440. return false;
  93441. }
  93442. if ($this->tokens[$prevIndex]->isGivenKind([T_AS, T_CONST, T_DOUBLE_COLON, T_FUNCTION, T_GOTO, CT::T_GROUP_IMPORT_BRACE_OPEN, CT::T_TYPE_COLON, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION]) || $this->tokens[$prevIndex]->isObjectOperator()) {
  93443. return false;
  93444. }
  93445. if (
  93446. $this->tokens[$prevIndex]->isGivenKind(T_CASE)
  93447. && $this->tokens->isAllTokenKindsFound([FCT::T_ENUM])
  93448. ) {
  93449. $enumSwitchIndex = $this->tokens->getPrevTokenOfKind($index, [[T_SWITCH], [T_ENUM]]);
  93450. if (!$this->tokens[$enumSwitchIndex]->isGivenKind(T_SWITCH)) {
  93451. return false;
  93452. }
  93453. }
  93454. while ($this->tokens[$prevIndex]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_NS_SEPARATOR, T_STRING, CT::T_ARRAY_TYPEHINT])) {
  93455. $prevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex);
  93456. }
  93457. if ($this->tokens[$prevIndex]->isGivenKind([CT::T_CONST_IMPORT, T_EXTENDS, CT::T_FUNCTION_IMPORT, T_IMPLEMENTS, T_INSTANCEOF, T_INSTEADOF, T_NAMESPACE, T_NEW, CT::T_NULLABLE_TYPE, CT::T_TYPE_COLON, T_USE, CT::T_USE_TRAIT, CT::T_TYPE_INTERSECTION, CT::T_TYPE_ALTERNATION, T_CONST, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE])) {
  93458. return false;
  93459. }
  93460. if ($this->tokens[$nextIndex]->equals('&') && $this->tokens[$this->tokens->getNextMeaningfulToken($nextIndex)]->isGivenKind(T_VARIABLE)) {
  93461. $checkIndex = $this->tokens->getPrevTokenOfKind($prevIndex, [';', '{', '}', [T_FUNCTION], [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]);
  93462. if ($this->tokens[$checkIndex]->isGivenKind(T_FUNCTION)) {
  93463. return false;
  93464. }
  93465. }
  93466. if ($this->tokens[$prevIndex]->equals(',')) {
  93467. $checkIndex = $prevIndex;
  93468. while ($this->tokens[$checkIndex]->equalsAny([',', [T_AS], [CT::T_NAMESPACE_OPERATOR], [T_NS_SEPARATOR], [T_STRING]])) {
  93469. $checkIndex = $this->tokens->getPrevMeaningfulToken($checkIndex);
  93470. }
  93471. if ($this->tokens[$checkIndex]->isGivenKind([T_EXTENDS, CT::T_GROUP_IMPORT_BRACE_OPEN, T_IMPLEMENTS, T_USE, CT::T_USE_TRAIT])) {
  93472. return false;
  93473. }
  93474. }
  93475. if ($this->tokens[$prevIndex]->equals('[') && $this->tokens[$nextIndex]->equals(']')) {
  93476. $checkToken = $this->tokens[$this->tokens->getNextMeaningfulToken($nextIndex)];
  93477. if ($checkToken->equals('"') || $checkToken->isGivenKind([T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_ENCAPSED_AND_WHITESPACE, T_VARIABLE])) {
  93478. return false;
  93479. }
  93480. }
  93481. if (AttributeAnalyzer::isAttribute($this->tokens, $index)) {
  93482. return false;
  93483. }
  93484. if ($this->tokens[$nextIndex]->equals(':')) {
  93485. if ($this->gotoLabelAnalyzer->belongsToGoToLabel($this->tokens, $nextIndex)) {
  93486. return false;
  93487. }
  93488. }
  93489. while ($this->tokens[$prevIndex]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_NS_SEPARATOR, T_STRING, CT::T_TYPE_ALTERNATION])) {
  93490. $prevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex);
  93491. }
  93492. if ($this->tokens[$prevIndex]->equals('(')) {
  93493. $prevPrevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex);
  93494. if ($this->tokens[$prevPrevIndex]->isGivenKind(T_CATCH)) {
  93495. return false;
  93496. }
  93497. }
  93498. return true;
  93499. }
  93500. public function isUnarySuccessorOperator(int $index): bool
  93501. {
  93502. static $allowedPrevToken = [
  93503. ']',
  93504. [T_STRING],
  93505. [T_VARIABLE],
  93506. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  93507. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  93508. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  93509. ];
  93510. $tokens = $this->tokens;
  93511. $token = $tokens[$index];
  93512. if (!$token->isGivenKind([T_INC, T_DEC])) {
  93513. return false;
  93514. }
  93515. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  93516. return $prevToken->equalsAny($allowedPrevToken);
  93517. }
  93518. public function isUnaryPredecessorOperator(int $index): bool
  93519. {
  93520. static $potentialSuccessorOperator = [T_INC, T_DEC];
  93521. static $potentialBinaryOperator = ['+', '-', '&', [CT::T_RETURN_REF]];
  93522. static $otherOperators;
  93523. if (null === $otherOperators) {
  93524. $otherOperators = ['!', '~', '@', [T_ELLIPSIS]];
  93525. }
  93526. static $disallowedPrevTokens;
  93527. if (null === $disallowedPrevTokens) {
  93528. $disallowedPrevTokens = [
  93529. ']',
  93530. '}',
  93531. ')',
  93532. '"',
  93533. '`',
  93534. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  93535. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  93536. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  93537. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  93538. [T_CLASS_C],
  93539. [T_CONSTANT_ENCAPSED_STRING],
  93540. [T_DEC],
  93541. [T_DIR],
  93542. [T_DNUMBER],
  93543. [T_FILE],
  93544. [T_FUNC_C],
  93545. [T_INC],
  93546. [T_LINE],
  93547. [T_LNUMBER],
  93548. [T_METHOD_C],
  93549. [T_NS_C],
  93550. [T_STRING],
  93551. [T_TRAIT_C],
  93552. [T_VARIABLE],
  93553. ];
  93554. }
  93555. $tokens = $this->tokens;
  93556. $token = $tokens[$index];
  93557. if ($token->isGivenKind($potentialSuccessorOperator)) {
  93558. return !$this->isUnarySuccessorOperator($index);
  93559. }
  93560. if ($token->equalsAny($otherOperators)) {
  93561. return true;
  93562. }
  93563. if (!$token->equalsAny($potentialBinaryOperator)) {
  93564. return false;
  93565. }
  93566. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  93567. if (!$prevToken->equalsAny($disallowedPrevTokens)) {
  93568. return true;
  93569. }
  93570. if (!$token->equals('&') || !$prevToken->isGivenKind(T_STRING)) {
  93571. return false;
  93572. }
  93573. static $searchTokens = [
  93574. ';',
  93575. '{',
  93576. '}',
  93577. [T_DOUBLE_ARROW],
  93578. [T_FN],
  93579. [T_FUNCTION],
  93580. [T_OPEN_TAG],
  93581. [T_OPEN_TAG_WITH_ECHO],
  93582. ];
  93583. $prevToken = $tokens[$tokens->getPrevTokenOfKind($index, $searchTokens)];
  93584. return $prevToken->isGivenKind([T_FN, T_FUNCTION]);
  93585. }
  93586. public function isBinaryOperator(int $index): bool
  93587. {
  93588. static $nonArrayOperators = [
  93589. '=' => true,
  93590. '*' => true,
  93591. '/' => true,
  93592. '%' => true,
  93593. '<' => true,
  93594. '>' => true,
  93595. '|' => true,
  93596. '^' => true,
  93597. '.' => true,
  93598. ];
  93599. static $potentialUnaryNonArrayOperators = [
  93600. '+' => true,
  93601. '-' => true,
  93602. '&' => true,
  93603. ];
  93604. static $arrayOperators;
  93605. if (null === $arrayOperators) {
  93606. $arrayOperators = [
  93607. T_AND_EQUAL => true,
  93608. T_BOOLEAN_AND => true,
  93609. T_BOOLEAN_OR => true,
  93610. T_CONCAT_EQUAL => true,
  93611. T_DIV_EQUAL => true,
  93612. T_DOUBLE_ARROW => true,
  93613. T_IS_EQUAL => true,
  93614. T_IS_GREATER_OR_EQUAL => true,
  93615. T_IS_IDENTICAL => true,
  93616. T_IS_NOT_EQUAL => true,
  93617. T_IS_NOT_IDENTICAL => true,
  93618. T_IS_SMALLER_OR_EQUAL => true,
  93619. T_LOGICAL_AND => true,
  93620. T_LOGICAL_OR => true,
  93621. T_LOGICAL_XOR => true,
  93622. T_MINUS_EQUAL => true,
  93623. T_MOD_EQUAL => true,
  93624. T_MUL_EQUAL => true,
  93625. T_OR_EQUAL => true,
  93626. T_PLUS_EQUAL => true,
  93627. T_POW => true,
  93628. T_POW_EQUAL => true,
  93629. T_SL => true,
  93630. T_SL_EQUAL => true,
  93631. T_SR => true,
  93632. T_SR_EQUAL => true,
  93633. T_XOR_EQUAL => true,
  93634. T_SPACESHIP => true,
  93635. T_COALESCE => true,
  93636. T_COALESCE_EQUAL => true,
  93637. ];
  93638. }
  93639. $tokens = $this->tokens;
  93640. $token = $tokens[$index];
  93641. if ($token->isGivenKind([T_INLINE_HTML, T_ENCAPSED_AND_WHITESPACE, CT::T_TYPE_INTERSECTION])) {
  93642. return false;
  93643. }
  93644. if (isset($potentialUnaryNonArrayOperators[$token->getContent()])) {
  93645. return !$this->isUnaryPredecessorOperator($index);
  93646. }
  93647. if ($token->isArray()) {
  93648. return isset($arrayOperators[$token->getId()]);
  93649. }
  93650. if (isset($nonArrayOperators[$token->getContent()])) {
  93651. return true;
  93652. }
  93653. return false;
  93654. }
  93655. public function isWhilePartOfDoWhile(int $index): bool
  93656. {
  93657. $tokens = $this->tokens;
  93658. $token = $tokens[$index];
  93659. if (!$token->isGivenKind(T_WHILE)) {
  93660. throw new \LogicException(\sprintf('No T_WHILE at given index %d, got "%s".', $index, $token->getName()));
  93661. }
  93662. $endIndex = $tokens->getPrevMeaningfulToken($index);
  93663. if (!$tokens[$endIndex]->equals('}')) {
  93664. return false;
  93665. }
  93666. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $endIndex);
  93667. $beforeStartIndex = $tokens->getPrevMeaningfulToken($startIndex);
  93668. return $tokens[$beforeStartIndex]->isGivenKind(T_DO);
  93669. }
  93670. public function isEnumCase(int $caseIndex): bool
  93671. {
  93672. $tokens = $this->tokens;
  93673. $token = $tokens[$caseIndex];
  93674. if (!$token->isGivenKind(T_CASE)) {
  93675. throw new \LogicException(\sprintf(
  93676. 'No T_CASE given at index %d, got %s instead.',
  93677. $caseIndex,
  93678. $token->getName() ?? $token->getContent()
  93679. ));
  93680. }
  93681. if (!$tokens->isTokenKindFound(FCT::T_ENUM)) {
  93682. return false;
  93683. }
  93684. $prevIndex = $tokens->getPrevTokenOfKind($caseIndex, [[T_ENUM], [T_SWITCH]]);
  93685. return null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_ENUM);
  93686. }
  93687. public function isSuperGlobal(int $index): bool
  93688. {
  93689. static $superNames = [
  93690. '$_COOKIE' => true,
  93691. '$_ENV' => true,
  93692. '$_FILES' => true,
  93693. '$_GET' => true,
  93694. '$_POST' => true,
  93695. '$_REQUEST' => true,
  93696. '$_SERVER' => true,
  93697. '$_SESSION' => true,
  93698. '$GLOBALS' => true,
  93699. ];
  93700. $token = $this->tokens[$index];
  93701. if (!$token->isGivenKind(T_VARIABLE)) {
  93702. return false;
  93703. }
  93704. return isset($superNames[strtoupper($token->getContent())]);
  93705. }
  93706. private function findClassyElements(int $classIndex, int $index): array
  93707. {
  93708. $elements = [];
  93709. $curlyBracesLevel = 0;
  93710. $bracesLevel = 0;
  93711. ++$index;
  93712. for ($count = \count($this->tokens); $index < $count; ++$index) {
  93713. $token = $this->tokens[$index];
  93714. if ($token->isGivenKind(T_ENCAPSED_AND_WHITESPACE)) {
  93715. continue;
  93716. }
  93717. if ($token->isGivenKind(T_CLASS)) {
  93718. $nestedClassIndex = $index;
  93719. $index = $this->tokens->getNextMeaningfulToken($index);
  93720. if ($this->tokens[$index]->equals('(')) {
  93721. ++$index;
  93722. for ($nestedBracesLevel = 1; $index < $count; ++$index) {
  93723. $token = $this->tokens[$index];
  93724. if ($token->equals('(')) {
  93725. ++$nestedBracesLevel;
  93726. continue;
  93727. }
  93728. if ($token->equals(')')) {
  93729. --$nestedBracesLevel;
  93730. if (0 === $nestedBracesLevel) {
  93731. [$index, $newElements] = $this->findClassyElements($nestedClassIndex, $index);
  93732. $elements += $newElements;
  93733. break;
  93734. }
  93735. continue;
  93736. }
  93737. if ($token->isGivenKind(T_CLASS)) {
  93738. [$index, $newElements] = $this->findClassyElements($index, $index);
  93739. $elements += $newElements;
  93740. }
  93741. }
  93742. } else {
  93743. [$index, $newElements] = $this->findClassyElements($nestedClassIndex, $nestedClassIndex);
  93744. $elements += $newElements;
  93745. }
  93746. continue;
  93747. }
  93748. if ($token->equals('(')) {
  93749. ++$bracesLevel;
  93750. continue;
  93751. }
  93752. if ($token->equals(')')) {
  93753. --$bracesLevel;
  93754. continue;
  93755. }
  93756. if ($token->equals('{')) {
  93757. ++$curlyBracesLevel;
  93758. continue;
  93759. }
  93760. if ($token->equals('}')) {
  93761. --$curlyBracesLevel;
  93762. if (0 === $curlyBracesLevel) {
  93763. break;
  93764. }
  93765. continue;
  93766. }
  93767. if (1 !== $curlyBracesLevel || !$token->isArray()) {
  93768. continue;
  93769. }
  93770. if (0 === $bracesLevel && $token->isGivenKind(T_VARIABLE)) {
  93771. $elements[$index] = [
  93772. 'classIndex' => $classIndex,
  93773. 'token' => $token,
  93774. 'type' => 'property',
  93775. ];
  93776. continue;
  93777. }
  93778. if ($token->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
  93779. $index = $this->tokens->getNextTokenOfKind($index, [[CT::T_PROPERTY_HOOK_BRACE_CLOSE]]);
  93780. continue;
  93781. }
  93782. if ($token->isGivenKind(T_FUNCTION)) {
  93783. $elements[$index] = [
  93784. 'classIndex' => $classIndex,
  93785. 'token' => $token,
  93786. 'type' => 'method',
  93787. ];
  93788. $functionNameIndex = $this->tokens->getNextMeaningfulToken($index);
  93789. if ('__construct' === $this->tokens[$functionNameIndex]->getContent()) {
  93790. $openParenthesis = $this->tokens->getNextMeaningfulToken($functionNameIndex);
  93791. $closeParenthesis = $this->tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
  93792. foreach ($this->tokens->findGivenKind([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, FCT::T_READONLY], $openParenthesis, $closeParenthesis) as $kindElements) {
  93793. foreach (array_keys($kindElements) as $promotedPropertyModifierIndex) {
  93794. $promotedPropertyVariableIndex = $this->tokens->getNextTokenOfKind($promotedPropertyModifierIndex, [[T_VARIABLE]]);
  93795. $elements[$promotedPropertyVariableIndex] = [
  93796. 'classIndex' => $classIndex,
  93797. 'token' => $this->tokens[$promotedPropertyVariableIndex],
  93798. 'type' => 'promoted_property',
  93799. ];
  93800. }
  93801. }
  93802. }
  93803. } elseif ($token->isGivenKind(T_CONST)) {
  93804. $elements[$index] = [
  93805. 'classIndex' => $classIndex,
  93806. 'token' => $token,
  93807. 'type' => 'const',
  93808. ];
  93809. } elseif ($token->isGivenKind(CT::T_USE_TRAIT)) {
  93810. $elements[$index] = [
  93811. 'classIndex' => $classIndex,
  93812. 'token' => $token,
  93813. 'type' => 'trait_import',
  93814. ];
  93815. } elseif ($token->isGivenKind(T_CASE)) {
  93816. $elements[$index] = [
  93817. 'classIndex' => $classIndex,
  93818. 'token' => $token,
  93819. 'type' => 'case',
  93820. ];
  93821. }
  93822. }
  93823. return [$index, $elements];
  93824. }
  93825. }
  93826. <?php
  93827. declare(strict_types=1);
  93828. namespace PhpCsFixer\Tokenizer;
  93829. use PhpCsFixer\Console\Application;
  93830. use PhpCsFixer\Hasher;
  93831. use PhpCsFixer\Preg;
  93832. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  93833. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  93834. use PhpCsFixer\Utils;
  93835. /**
  93836. @extends
  93837. */
  93838. class Tokens extends \SplFixedArray
  93839. {
  93840. public const BLOCK_TYPE_PARENTHESIS_BRACE = 1;
  93841. public const BLOCK_TYPE_CURLY_BRACE = 2;
  93842. public const BLOCK_TYPE_INDEX_SQUARE_BRACE = 3;
  93843. public const BLOCK_TYPE_ARRAY_SQUARE_BRACE = 4;
  93844. public const BLOCK_TYPE_DYNAMIC_PROP_BRACE = 5;
  93845. public const BLOCK_TYPE_DYNAMIC_VAR_BRACE = 6;
  93846. public const BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE = 7;
  93847. public const BLOCK_TYPE_GROUP_IMPORT_BRACE = 8;
  93848. public const BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE = 9;
  93849. public const BLOCK_TYPE_BRACE_CLASS_INSTANTIATION = 10;
  93850. public const BLOCK_TYPE_ATTRIBUTE = 11;
  93851. public const BLOCK_TYPE_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS = 12;
  93852. public const BLOCK_TYPE_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE = 13;
  93853. public const BLOCK_TYPE_COMPLEX_STRING_VARIABLE = 14;
  93854. public const BLOCK_TYPE_PROPERTY_HOOK = 15;
  93855. private static array $cache = [];
  93856. private array $blockStartCache = [];
  93857. private array $blockEndCache = [];
  93858. private ?string $codeHash = null;
  93859. private ?string $collectionHash = null;
  93860. private bool $changed = false;
  93861. private array $foundTokenKinds = [];
  93862. private ?array $namespaceDeclarations = null;
  93863. public function __clone()
  93864. {
  93865. foreach ($this as $key => $val) {
  93866. $this[$key] = clone $val;
  93867. }
  93868. }
  93869. public static function clearCache(?string $key = null): void
  93870. {
  93871. if (null === $key) {
  93872. self::$cache = [];
  93873. return;
  93874. }
  93875. unset(self::$cache[$key]);
  93876. }
  93877. public static function detectBlockType(Token $token): ?array
  93878. {
  93879. static $blockEdgeKinds = null;
  93880. if (null === $blockEdgeKinds) {
  93881. $blockEdgeKinds = [];
  93882. foreach (self::getBlockEdgeDefinitions() as $type => $definition) {
  93883. $blockEdgeKinds[
  93884. \is_string($definition['start']) ? $definition['start'] : $definition['start'][0]
  93885. ] = ['type' => $type, 'isStart' => true];
  93886. $blockEdgeKinds[
  93887. \is_string($definition['end']) ? $definition['end'] : $definition['end'][0]
  93888. ] = ['type' => $type, 'isStart' => false];
  93889. }
  93890. }
  93891. $tokenKind = $token->isArray() ? $token->getId() : $token->getContent();
  93892. return $blockEdgeKinds[$tokenKind] ?? null;
  93893. }
  93894. public static function fromArray($array, $saveIndices = null): self
  93895. {
  93896. $tokens = new self(\count($array));
  93897. if (false !== $saveIndices && !array_is_list($array)) {
  93898. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  93899. 'Parameter "array" should be a list. This will be enforced in version %d.0.',
  93900. Application::getMajorVersion() + 1
  93901. )));
  93902. foreach ($array as $key => $val) {
  93903. $tokens[$key] = $val;
  93904. }
  93905. } else {
  93906. $index = 0;
  93907. foreach ($array as $val) {
  93908. $tokens[$index++] = $val;
  93909. }
  93910. }
  93911. $tokens->clearChanged();
  93912. $tokens->generateCode();
  93913. return $tokens;
  93914. }
  93915. public static function fromCode(string $code): self
  93916. {
  93917. $codeHash = self::calculateHash($code);
  93918. if (self::hasCache($codeHash)) {
  93919. $tokens = self::getCache($codeHash);
  93920. if ($codeHash === $tokens->codeHash) {
  93921. $tokens->clearEmptyTokens();
  93922. $tokens->clearChanged();
  93923. return $tokens;
  93924. }
  93925. }
  93926. $tokens = new self();
  93927. $tokens->setCode($code);
  93928. $tokens->clearChanged();
  93929. return $tokens;
  93930. }
  93931. public static function getBlockEdgeDefinitions(): array
  93932. {
  93933. return [
  93934. self::BLOCK_TYPE_CURLY_BRACE => [
  93935. 'start' => '{',
  93936. 'end' => '}',
  93937. ],
  93938. self::BLOCK_TYPE_PARENTHESIS_BRACE => [
  93939. 'start' => '(',
  93940. 'end' => ')',
  93941. ],
  93942. self::BLOCK_TYPE_INDEX_SQUARE_BRACE => [
  93943. 'start' => '[',
  93944. 'end' => ']',
  93945. ],
  93946. self::BLOCK_TYPE_ARRAY_SQUARE_BRACE => [
  93947. 'start' => [CT::T_ARRAY_SQUARE_BRACE_OPEN, '['],
  93948. 'end' => [CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']'],
  93949. ],
  93950. self::BLOCK_TYPE_DYNAMIC_PROP_BRACE => [
  93951. 'start' => [CT::T_DYNAMIC_PROP_BRACE_OPEN, '{'],
  93952. 'end' => [CT::T_DYNAMIC_PROP_BRACE_CLOSE, '}'],
  93953. ],
  93954. self::BLOCK_TYPE_DYNAMIC_VAR_BRACE => [
  93955. 'start' => [CT::T_DYNAMIC_VAR_BRACE_OPEN, '{'],
  93956. 'end' => [CT::T_DYNAMIC_VAR_BRACE_CLOSE, '}'],
  93957. ],
  93958. self::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE => [
  93959. 'start' => [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{'],
  93960. 'end' => [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, '}'],
  93961. ],
  93962. self::BLOCK_TYPE_GROUP_IMPORT_BRACE => [
  93963. 'start' => [CT::T_GROUP_IMPORT_BRACE_OPEN, '{'],
  93964. 'end' => [CT::T_GROUP_IMPORT_BRACE_CLOSE, '}'],
  93965. ],
  93966. self::BLOCK_TYPE_DESTRUCTURING_SQUARE_BRACE => [
  93967. 'start' => [CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '['],
  93968. 'end' => [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']'],
  93969. ],
  93970. self::BLOCK_TYPE_BRACE_CLASS_INSTANTIATION => [
  93971. 'start' => [CT::T_BRACE_CLASS_INSTANTIATION_OPEN, '('],
  93972. 'end' => [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE, ')'],
  93973. ],
  93974. self::BLOCK_TYPE_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS => [
  93975. 'start' => [CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, '('],
  93976. 'end' => [CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE, ')'],
  93977. ],
  93978. self::BLOCK_TYPE_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE => [
  93979. 'start' => [CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, '{'],
  93980. 'end' => [CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, '}'],
  93981. ],
  93982. self::BLOCK_TYPE_COMPLEX_STRING_VARIABLE => [
  93983. 'start' => [T_DOLLAR_OPEN_CURLY_BRACES, '${'],
  93984. 'end' => [CT::T_DOLLAR_CLOSE_CURLY_BRACES, '}'],
  93985. ],
  93986. self::BLOCK_TYPE_PROPERTY_HOOK => [
  93987. 'start' => [CT::T_PROPERTY_HOOK_BRACE_OPEN, '{'],
  93988. 'end' => [CT::T_PROPERTY_HOOK_BRACE_CLOSE, '}'],
  93989. ],
  93990. self::BLOCK_TYPE_ATTRIBUTE => [
  93991. 'start' => [FCT::T_ATTRIBUTE, '#['],
  93992. 'end' => [CT::T_ATTRIBUTE_CLOSE, ']'],
  93993. ],
  93994. ];
  93995. }
  93996. #[\ReturnTypeWillChange]
  93997. public function setSize($size): bool
  93998. {
  93999. throw new \RuntimeException('Changing tokens collection size explicitly is not allowed.');
  94000. }
  94001. public function offsetUnset($index): void
  94002. {
  94003. if (\count($this) - 1 !== $index) {
  94004. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  94005. 'Tokens should be a list - only the last index can be unset. This will be enforced in version %d.0.',
  94006. Application::getMajorVersion() + 1
  94007. )));
  94008. }
  94009. if (isset($this[$index])) {
  94010. if (isset($this->blockStartCache[$index])) {
  94011. unset($this->blockEndCache[$this->blockStartCache[$index]], $this->blockStartCache[$index]);
  94012. }
  94013. if (isset($this->blockEndCache[$index])) {
  94014. unset($this->blockStartCache[$this->blockEndCache[$index]], $this->blockEndCache[$index]);
  94015. }
  94016. $this->unregisterFoundToken($this[$index]);
  94017. $this->changed = true;
  94018. $this->collectionHash = null;
  94019. self::clearCache($this->codeHash);
  94020. $this->codeHash = null;
  94021. $this->namespaceDeclarations = null;
  94022. }
  94023. parent::offsetUnset($index);
  94024. }
  94025. public function offsetSet($index, $newval): void
  94026. {
  94027. if (0 > $index || \count($this) <= $index) {
  94028. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  94029. 'Tokens should be a list - index must be within the existing range. This will be enforced in version %d.0.',
  94030. Application::getMajorVersion() + 1
  94031. )));
  94032. }
  94033. if (isset($this[$index])) {
  94034. if (isset($this->blockStartCache[$index])) {
  94035. unset($this->blockEndCache[$this->blockStartCache[$index]], $this->blockStartCache[$index]);
  94036. }
  94037. if (isset($this->blockEndCache[$index])) {
  94038. unset($this->blockStartCache[$this->blockEndCache[$index]], $this->blockEndCache[$index]);
  94039. }
  94040. }
  94041. if (!isset($this[$index]) || !$this[$index]->equals($newval)) {
  94042. if (isset($this[$index])) {
  94043. $this->unregisterFoundToken($this[$index]);
  94044. }
  94045. $this->changed = true;
  94046. $this->collectionHash = null;
  94047. self::clearCache($this->codeHash);
  94048. $this->codeHash = null;
  94049. $this->namespaceDeclarations = null;
  94050. $this->registerFoundToken($newval);
  94051. }
  94052. parent::offsetSet($index, $newval);
  94053. }
  94054. public function clearChanged(): void
  94055. {
  94056. $this->changed = false;
  94057. }
  94058. public function clearEmptyTokens(): void
  94059. {
  94060. if (!$this->isTokenKindFound('')) {
  94061. return;
  94062. }
  94063. $limit = \count($this);
  94064. for ($index = 0; $index < $limit; ++$index) {
  94065. if ($this->isEmptyAt($index)) {
  94066. break;
  94067. }
  94068. }
  94069. for ($count = $index; $index < $limit; ++$index) {
  94070. if (!$this->isEmptyAt($index)) {
  94071. $buffer = $this[$count];
  94072. parent::offsetSet($count, $this[$index]);
  94073. parent::offsetSet($index, $buffer);
  94074. if (isset($this->blockStartCache[$index])) {
  94075. $otherEndIndex = $this->blockStartCache[$index];
  94076. unset($this->blockStartCache[$index]);
  94077. $this->blockStartCache[$count] = $otherEndIndex;
  94078. $this->blockEndCache[$otherEndIndex] = $count;
  94079. }
  94080. if (isset($this->blockEndCache[$index])) {
  94081. $otherEndIndex = $this->blockEndCache[$index];
  94082. unset($this->blockEndCache[$index]);
  94083. $this->blockStartCache[$otherEndIndex] = $count;
  94084. $this->blockEndCache[$count] = $otherEndIndex;
  94085. }
  94086. ++$count;
  94087. }
  94088. }
  94089. $this->namespaceDeclarations = null;
  94090. $this->foundTokenKinds[''] = 0;
  94091. $this->collectionHash = null;
  94092. $this->updateSizeByTrimmingTrailingEmptyTokens();
  94093. }
  94094. public function ensureWhitespaceAtIndex(int $index, int $indexOffset, string $whitespace): bool
  94095. {
  94096. $removeLastCommentLine = static function (self $tokens, int $index, int $indexOffset, string $whitespace): string {
  94097. $token = $tokens[$index];
  94098. if (1 === $indexOffset && $token->isGivenKind(T_OPEN_TAG)) {
  94099. if (str_starts_with($whitespace, "\r\n")) {
  94100. $tokens[$index] = new Token([T_OPEN_TAG, rtrim($token->getContent())."\r\n"]);
  94101. return \strlen($whitespace) > 2
  94102. ? substr($whitespace, 2)
  94103. : '';
  94104. }
  94105. $tokens[$index] = new Token([T_OPEN_TAG, rtrim($token->getContent()).$whitespace[0]]);
  94106. return \strlen($whitespace) > 1
  94107. ? substr($whitespace, 1)
  94108. : '';
  94109. }
  94110. return $whitespace;
  94111. };
  94112. if ($this[$index]->isWhitespace()) {
  94113. $whitespace = $removeLastCommentLine($this, $index - 1, $indexOffset, $whitespace);
  94114. if ('' === $whitespace) {
  94115. $this->clearAt($index);
  94116. } else {
  94117. $this[$index] = new Token([T_WHITESPACE, $whitespace]);
  94118. }
  94119. return false;
  94120. }
  94121. $whitespace = $removeLastCommentLine($this, $index, $indexOffset, $whitespace);
  94122. if ('' === $whitespace) {
  94123. return false;
  94124. }
  94125. $this->insertAt(
  94126. $index + $indexOffset,
  94127. [new Token([T_WHITESPACE, $whitespace])]
  94128. );
  94129. return true;
  94130. }
  94131. public function findBlockEnd(int $type, int $searchIndex): int
  94132. {
  94133. return $this->findOppositeBlockEdge($type, $searchIndex, true);
  94134. }
  94135. public function findBlockStart(int $type, int $searchIndex): int
  94136. {
  94137. return $this->findOppositeBlockEdge($type, $searchIndex, false);
  94138. }
  94139. public function findGivenKind($possibleKind, int $start = 0, ?int $end = null): array
  94140. {
  94141. if (null === $end) {
  94142. $end = \count($this);
  94143. }
  94144. $elements = [];
  94145. $possibleKinds = (array) $possibleKind;
  94146. foreach ($possibleKinds as $kind) {
  94147. $elements[$kind] = [];
  94148. }
  94149. $possibleKinds = array_filter($possibleKinds, fn ($kind): bool => $this->isTokenKindFound($kind));
  94150. if (\count($possibleKinds) > 0) {
  94151. for ($i = $start; $i < $end; ++$i) {
  94152. $token = $this[$i];
  94153. if ($token->isGivenKind($possibleKinds)) {
  94154. $elements[$token->getId()][$i] = $token;
  94155. }
  94156. }
  94157. }
  94158. return \is_array($possibleKind) ? $elements : $elements[$possibleKind];
  94159. }
  94160. public function generateCode(): string
  94161. {
  94162. $code = $this->generatePartialCode(0, \count($this) - 1);
  94163. if (null === $this->codeHash) {
  94164. $this->changeCodeHash(self::calculateHash($code));
  94165. }
  94166. return $code;
  94167. }
  94168. public function generatePartialCode(int $start, int $end): string
  94169. {
  94170. $code = '';
  94171. for ($i = $start; $i <= $end; ++$i) {
  94172. $code .= $this[$i]->getContent();
  94173. }
  94174. return $code;
  94175. }
  94176. public function getCodeHash(): string
  94177. {
  94178. if (null === $this->codeHash) {
  94179. $code = $this->generatePartialCode(0, \count($this) - 1);
  94180. $this->changeCodeHash(self::calculateHash($code));
  94181. }
  94182. return $this->codeHash;
  94183. }
  94184. public function getCollectionHash(): string
  94185. {
  94186. if (null === $this->collectionHash) {
  94187. $this->collectionHash = self::calculateHash(
  94188. $this->getCodeHash()
  94189. .'#'
  94190. .\count($this)
  94191. .'#'
  94192. .implode(
  94193. '',
  94194. array_map(static fn (?Token $token): ?int => null !== $token ? $token->getId() : null, $this->toArray())
  94195. )
  94196. );
  94197. }
  94198. return $this->collectionHash;
  94199. }
  94200. public function getNextNonWhitespace(int $index, ?string $whitespaces = null): ?int
  94201. {
  94202. return $this->getNonWhitespaceSibling($index, 1, $whitespaces);
  94203. }
  94204. public function getNextTokenOfKind(int $index, array $tokens = [], bool $caseSensitive = true): ?int
  94205. {
  94206. return $this->getTokenOfKindSibling($index, 1, $tokens, $caseSensitive);
  94207. }
  94208. public function getNonWhitespaceSibling(int $index, int $direction, ?string $whitespaces = null): ?int
  94209. {
  94210. while (true) {
  94211. $index += $direction;
  94212. if (!$this->offsetExists($index)) {
  94213. return null;
  94214. }
  94215. if (!$this[$index]->isWhitespace($whitespaces)) {
  94216. return $index;
  94217. }
  94218. }
  94219. }
  94220. public function getPrevNonWhitespace(int $index, ?string $whitespaces = null): ?int
  94221. {
  94222. return $this->getNonWhitespaceSibling($index, -1, $whitespaces);
  94223. }
  94224. public function getPrevTokenOfKind(int $index, array $tokens = [], bool $caseSensitive = true): ?int
  94225. {
  94226. return $this->getTokenOfKindSibling($index, -1, $tokens, $caseSensitive);
  94227. }
  94228. public function getTokenOfKindSibling(int $index, int $direction, array $tokens = [], bool $caseSensitive = true): ?int
  94229. {
  94230. $tokens = array_values(
  94231. array_filter(
  94232. $tokens,
  94233. fn ($token): bool => $this->isTokenKindFound($this->extractTokenKind($token))
  94234. )
  94235. );
  94236. if (0 === \count($tokens)) {
  94237. return null;
  94238. }
  94239. while (true) {
  94240. $index += $direction;
  94241. if (!$this->offsetExists($index)) {
  94242. return null;
  94243. }
  94244. if ($this[$index]->equalsAny($tokens, $caseSensitive)) {
  94245. return $index;
  94246. }
  94247. }
  94248. }
  94249. public function getTokenNotOfKindSibling(int $index, int $direction, array $tokens = []): ?int
  94250. {
  94251. return $this->getTokenNotOfKind(
  94252. $index,
  94253. $direction,
  94254. fn (int $a): bool => $this[$a]->equalsAny($tokens),
  94255. );
  94256. }
  94257. public function getTokenNotOfKindsSibling(int $index, int $direction, array $kinds = []): ?int
  94258. {
  94259. return $this->getTokenNotOfKind(
  94260. $index,
  94261. $direction,
  94262. fn (int $index): bool => $this[$index]->isGivenKind($kinds),
  94263. );
  94264. }
  94265. public function getMeaningfulTokenSibling(int $index, int $direction): ?int
  94266. {
  94267. return $this->getTokenNotOfKindsSibling(
  94268. $index,
  94269. $direction,
  94270. [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT]
  94271. );
  94272. }
  94273. public function getNonEmptySibling(int $index, int $direction): ?int
  94274. {
  94275. while (true) {
  94276. $index += $direction;
  94277. if (!$this->offsetExists($index)) {
  94278. return null;
  94279. }
  94280. if (!$this->isEmptyAt($index)) {
  94281. return $index;
  94282. }
  94283. }
  94284. }
  94285. public function getNextMeaningfulToken(int $index): ?int
  94286. {
  94287. return $this->getMeaningfulTokenSibling($index, 1);
  94288. }
  94289. public function getPrevMeaningfulToken(int $index): ?int
  94290. {
  94291. return $this->getMeaningfulTokenSibling($index, -1);
  94292. }
  94293. public function findSequence(array $sequence, int $start = 0, ?int $end = null, $caseSensitive = true): ?array
  94294. {
  94295. $sequenceCount = \count($sequence);
  94296. if (0 === $sequenceCount) {
  94297. throw new \InvalidArgumentException('Invalid sequence.');
  94298. }
  94299. $end = null === $end ? \count($this) - 1 : min($end, \count($this) - 1);
  94300. if ($start + $sequenceCount - 1 > $end) {
  94301. return null;
  94302. }
  94303. $nonMeaningFullKind = [T_COMMENT, T_DOC_COMMENT, T_WHITESPACE];
  94304. foreach ($sequence as $key => $token) {
  94305. if (!$token instanceof Token) {
  94306. if (\is_array($token) && !isset($token[1])) {
  94307. $token[1] = 'DUMMY';
  94308. }
  94309. $token = new Token($token);
  94310. }
  94311. if ($token->isGivenKind($nonMeaningFullKind)) {
  94312. throw new \InvalidArgumentException(\sprintf('Non-meaningful token at position: "%s".', $key));
  94313. }
  94314. if ('' === $token->getContent()) {
  94315. throw new \InvalidArgumentException(\sprintf('Non-meaningful (empty) token at position: "%s".', $key));
  94316. }
  94317. }
  94318. foreach ($sequence as $token) {
  94319. if (!$this->isTokenKindFound($this->extractTokenKind($token))) {
  94320. return null;
  94321. }
  94322. }
  94323. $firstKey = array_key_first($sequence);
  94324. $firstCs = self::isKeyCaseSensitive($caseSensitive, $firstKey);
  94325. $firstToken = $sequence[$firstKey];
  94326. unset($sequence[$firstKey]);
  94327. $index = $start - 1;
  94328. while ($index <= $end) {
  94329. $index = $this->getNextTokenOfKind($index, [$firstToken], $firstCs);
  94330. if (null === $index || $index > $end) {
  94331. return null;
  94332. }
  94333. $result = [$index => $this[$index]];
  94334. $currIdx = $index;
  94335. foreach ($sequence as $key => $token) {
  94336. $currIdx = $this->getNextMeaningfulToken($currIdx);
  94337. if (null === $currIdx || $currIdx > $end) {
  94338. return null;
  94339. }
  94340. if (!$this[$currIdx]->equals($token, self::isKeyCaseSensitive($caseSensitive, $key))) {
  94341. continue 2;
  94342. }
  94343. $result[$currIdx] = $this[$currIdx];
  94344. }
  94345. if (\count($sequence) < \count($result)) {
  94346. return $result;
  94347. }
  94348. }
  94349. return null;
  94350. }
  94351. public function insertAt(int $index, $items): void
  94352. {
  94353. $this->insertSlices([$index => $items]);
  94354. }
  94355. public function insertSlices(array $slices): void
  94356. {
  94357. $itemsCount = 0;
  94358. foreach ($slices as $slice) {
  94359. $itemsCount += \is_array($slice) || $slice instanceof self ? \count($slice) : 1;
  94360. }
  94361. if (0 === $itemsCount) {
  94362. return;
  94363. }
  94364. $this->changed = true;
  94365. $this->collectionHash = null;
  94366. self::clearCache($this->codeHash);
  94367. $this->codeHash = null;
  94368. $this->namespaceDeclarations = null;
  94369. $this->blockStartCache = [];
  94370. $this->blockEndCache = [];
  94371. $oldSize = \count($this);
  94372. $this->updateSizeByIncreasingToNewSize($oldSize + $itemsCount);
  94373. krsort($slices);
  94374. $farthestSliceIndex = array_key_first($slices);
  94375. if (!\is_int($farthestSliceIndex) || $farthestSliceIndex > $oldSize) {
  94376. throw new \OutOfBoundsException(\sprintf('Cannot insert index "%s" outside of collection.', $farthestSliceIndex));
  94377. }
  94378. $previousSliceIndex = $oldSize;
  94379. foreach ($slices as $index => $slice) {
  94380. if (!\is_int($index) || $index < 0) {
  94381. throw new \OutOfBoundsException(\sprintf('Invalid index "%s".', $index));
  94382. }
  94383. $slice = \is_array($slice) || $slice instanceof self ? $slice : [$slice];
  94384. $sliceCount = \count($slice);
  94385. for ($i = $previousSliceIndex - 1; $i >= $index; --$i) {
  94386. parent::offsetSet($i + $itemsCount, $this[$i]);
  94387. }
  94388. $previousSliceIndex = $index;
  94389. $itemsCount -= $sliceCount;
  94390. foreach ($slice as $indexItem => $item) {
  94391. if ('' === $item->getContent()) {
  94392. throw new \InvalidArgumentException('Must not add empty token to collection.');
  94393. }
  94394. $this->registerFoundToken($item);
  94395. parent::offsetSet($index + $itemsCount + $indexItem, $item);
  94396. }
  94397. }
  94398. }
  94399. public function isChanged(): bool
  94400. {
  94401. return $this->changed;
  94402. }
  94403. public function isEmptyAt(int $index): bool
  94404. {
  94405. $token = $this[$index];
  94406. return null === $token->getId() && '' === $token->getContent();
  94407. }
  94408. public function clearAt(int $index): void
  94409. {
  94410. $this[$index] = new Token('');
  94411. }
  94412. public function overrideRange(int $indexStart, int $indexEnd, iterable $items): void
  94413. {
  94414. $indexToChange = $indexEnd - $indexStart + 1;
  94415. $itemsCount = \count($items);
  94416. if ($itemsCount > $indexToChange) {
  94417. $placeholders = [];
  94418. while ($itemsCount > $indexToChange) {
  94419. $placeholders[] = new Token('__PLACEHOLDER__');
  94420. ++$indexToChange;
  94421. }
  94422. $this->insertAt($indexEnd + 1, $placeholders);
  94423. }
  94424. foreach ($items as $itemIndex => $item) {
  94425. $this[$indexStart + $itemIndex] = $item;
  94426. }
  94427. if ($itemsCount < $indexToChange) {
  94428. $this->clearRange($indexStart + $itemsCount, $indexEnd);
  94429. }
  94430. }
  94431. public function removeLeadingWhitespace(int $index, ?string $whitespaces = null): void
  94432. {
  94433. $this->removeWhitespaceSafely($index, -1, $whitespaces);
  94434. }
  94435. public function removeTrailingWhitespace(int $index, ?string $whitespaces = null): void
  94436. {
  94437. $this->removeWhitespaceSafely($index, 1, $whitespaces);
  94438. }
  94439. public function setCode(string $code): void
  94440. {
  94441. if ($code === $this->generateCode()) {
  94442. return;
  94443. }
  94444. $this->updateSizeToZero();
  94445. $tokens = token_get_all($code, TOKEN_PARSE);
  94446. $this->updateSizeByIncreasingToNewSize(\count($tokens));
  94447. foreach ($tokens as $index => $token) {
  94448. $this[$index] = new Token($token);
  94449. }
  94450. $this->applyTransformers();
  94451. if (\PHP_VERSION_ID < 8_00_00) {
  94452. $this->rewind();
  94453. }
  94454. $this->changed = true;
  94455. $this->collectionHash = null;
  94456. self::clearCache($this->codeHash);
  94457. $this->codeHash = null;
  94458. $this->namespaceDeclarations = null;
  94459. $this->blockStartCache = [];
  94460. $this->blockEndCache = [];
  94461. $this->changeCodeHash(self::calculateHash($code));
  94462. }
  94463. public function toJson(): string
  94464. {
  94465. $output = new \SplFixedArray(\count($this));
  94466. foreach ($this as $index => $token) {
  94467. $output[$index] = $token->toArray();
  94468. }
  94469. if (\PHP_VERSION_ID < 8_00_00) {
  94470. $this->rewind();
  94471. }
  94472. return json_encode($output, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
  94473. }
  94474. public function isAllTokenKindsFound(array $tokenKinds): bool
  94475. {
  94476. foreach ($tokenKinds as $tokenKind) {
  94477. if (0 === ($this->foundTokenKinds[$tokenKind] ?? 0)) {
  94478. return false;
  94479. }
  94480. }
  94481. return true;
  94482. }
  94483. public function isAnyTokenKindsFound(array $tokenKinds): bool
  94484. {
  94485. foreach ($tokenKinds as $tokenKind) {
  94486. if (0 !== ($this->foundTokenKinds[$tokenKind] ?? 0)) {
  94487. return true;
  94488. }
  94489. }
  94490. return false;
  94491. }
  94492. public function isTokenKindFound($tokenKind): bool
  94493. {
  94494. return 0 !== ($this->foundTokenKinds[$tokenKind] ?? 0);
  94495. }
  94496. public function countTokenKind($tokenKind): int
  94497. {
  94498. return $this->foundTokenKinds[$tokenKind] ?? 0;
  94499. }
  94500. public function clearRange(int $indexStart, int $indexEnd): void
  94501. {
  94502. for ($i = $indexStart; $i <= $indexEnd; ++$i) {
  94503. $this->clearAt($i);
  94504. }
  94505. }
  94506. public function isMonolithicPhp(): bool
  94507. {
  94508. if (1 !== ($this->countTokenKind(T_OPEN_TAG) + $this->countTokenKind(T_OPEN_TAG_WITH_ECHO))) {
  94509. return false;
  94510. }
  94511. return 0 === $this->countTokenKind(T_INLINE_HTML)
  94512. || (1 === $this->countTokenKind(T_INLINE_HTML) && Preg::match('/^#!.+$/', $this[0]->getContent()));
  94513. }
  94514. public function isPartialCodeMultiline(int $start, int $end): bool
  94515. {
  94516. for ($i = $start; $i <= $end; ++$i) {
  94517. if (str_contains($this[$i]->getContent(), "\n")) {
  94518. return true;
  94519. }
  94520. }
  94521. return false;
  94522. }
  94523. public function hasAlternativeSyntax(): bool
  94524. {
  94525. return $this->isAnyTokenKindsFound([
  94526. T_ENDDECLARE,
  94527. T_ENDFOR,
  94528. T_ENDFOREACH,
  94529. T_ENDIF,
  94530. T_ENDSWITCH,
  94531. T_ENDWHILE,
  94532. ]);
  94533. }
  94534. public function clearTokenAndMergeSurroundingWhitespace(int $index): void
  94535. {
  94536. $count = \count($this);
  94537. $this->clearAt($index);
  94538. if ($index === $count - 1) {
  94539. return;
  94540. }
  94541. $nextIndex = $this->getNonEmptySibling($index, 1);
  94542. if (null === $nextIndex || !$this[$nextIndex]->isWhitespace()) {
  94543. return;
  94544. }
  94545. $prevIndex = $this->getNonEmptySibling($index, -1);
  94546. if ($this[$prevIndex]->isWhitespace()) {
  94547. $this[$prevIndex] = new Token([T_WHITESPACE, $this[$prevIndex]->getContent().$this[$nextIndex]->getContent()]);
  94548. } elseif ($this->isEmptyAt($prevIndex + 1)) {
  94549. $this[$prevIndex + 1] = new Token([T_WHITESPACE, $this[$nextIndex]->getContent()]);
  94550. }
  94551. $this->clearAt($nextIndex);
  94552. }
  94553. public function getNamespaceDeclarations(): array
  94554. {
  94555. if (null === $this->namespaceDeclarations) {
  94556. $this->namespaceDeclarations = (new NamespacesAnalyzer())->getDeclarations($this);
  94557. }
  94558. return $this->namespaceDeclarations;
  94559. }
  94560. protected function applyTransformers(): void
  94561. {
  94562. $transformers = Transformers::createSingleton();
  94563. $transformers->transform($this);
  94564. }
  94565. private function updateSizeByIncreasingToNewSize(int $size): void
  94566. {
  94567. $currentSize = \count($this);
  94568. if ($currentSize >= $size) {
  94569. throw new \LogicException(\sprintf('Cannot use called method to decrease collection size (%d -> %d).', $currentSize, $size));
  94570. }
  94571. parent::setSize($size);
  94572. }
  94573. private function updateSizeToZero(): void
  94574. {
  94575. $currentSize = \count($this);
  94576. if (0 === $currentSize) {
  94577. return;
  94578. }
  94579. $this->changed = true;
  94580. $this->collectionHash = null;
  94581. self::clearCache($this->codeHash);
  94582. $this->codeHash = null;
  94583. $this->namespaceDeclarations = null;
  94584. $this->blockStartCache = [];
  94585. $this->blockEndCache = [];
  94586. parent::setSize(0);
  94587. }
  94588. private function updateSizeByTrimmingTrailingEmptyTokens(): void
  94589. {
  94590. $currentSize = \count($this);
  94591. if (0 === $currentSize) {
  94592. return;
  94593. }
  94594. $lastIndex = $currentSize - 1;
  94595. while ($lastIndex >= 0 && $this->isEmptyAt($lastIndex)) {
  94596. --$lastIndex;
  94597. }
  94598. parent::setSize($lastIndex + 1);
  94599. }
  94600. private function removeWhitespaceSafely(int $index, int $direction, ?string $whitespaces = null): void
  94601. {
  94602. $whitespaceIndex = $this->getNonEmptySibling($index, $direction);
  94603. if (isset($this[$whitespaceIndex]) && $this[$whitespaceIndex]->isWhitespace()) {
  94604. $newContent = '';
  94605. $tokenToCheck = $this[$whitespaceIndex];
  94606. if (isset($this[$whitespaceIndex - 1]) && $this[$whitespaceIndex - 1]->isComment() && !str_starts_with($this[$whitespaceIndex - 1]->getContent(), '/*')) {
  94607. [, $newContent, $whitespacesToCheck] = Preg::split('/^(\R)/', $this[$whitespaceIndex]->getContent(), -1, PREG_SPLIT_DELIM_CAPTURE);
  94608. if ('' === $whitespacesToCheck) {
  94609. return;
  94610. }
  94611. $tokenToCheck = new Token([T_WHITESPACE, $whitespacesToCheck]);
  94612. }
  94613. if (!$tokenToCheck->isWhitespace($whitespaces)) {
  94614. return;
  94615. }
  94616. if ('' === $newContent) {
  94617. $this->clearAt($whitespaceIndex);
  94618. } else {
  94619. $this[$whitespaceIndex] = new Token([T_WHITESPACE, $newContent]);
  94620. }
  94621. }
  94622. }
  94623. private function findOppositeBlockEdge(int $type, int $searchIndex, bool $findEnd): int
  94624. {
  94625. $blockEdgeDefinitions = self::getBlockEdgeDefinitions();
  94626. if (!isset($blockEdgeDefinitions[$type])) {
  94627. throw new \InvalidArgumentException(\sprintf('Invalid param type: "%s".', $type));
  94628. }
  94629. if ($findEnd && isset($this->blockStartCache[$searchIndex])) {
  94630. return $this->blockStartCache[$searchIndex];
  94631. }
  94632. if (!$findEnd && isset($this->blockEndCache[$searchIndex])) {
  94633. return $this->blockEndCache[$searchIndex];
  94634. }
  94635. $startEdge = $blockEdgeDefinitions[$type]['start'];
  94636. $endEdge = $blockEdgeDefinitions[$type]['end'];
  94637. $startIndex = $searchIndex;
  94638. $endIndex = \count($this) - 1;
  94639. $indexOffset = 1;
  94640. if (!$findEnd) {
  94641. [$startEdge, $endEdge] = [$endEdge, $startEdge];
  94642. $indexOffset = -1;
  94643. $endIndex = 0;
  94644. }
  94645. if (!$this[$startIndex]->equals($startEdge)) {
  94646. throw new \InvalidArgumentException(\sprintf('Invalid param $startIndex - not a proper block "%s".', $findEnd ? 'start' : 'end'));
  94647. }
  94648. $blockLevel = 0;
  94649. for ($index = $startIndex; $index !== $endIndex; $index += $indexOffset) {
  94650. $token = $this[$index];
  94651. if ($token->equals($startEdge)) {
  94652. ++$blockLevel;
  94653. continue;
  94654. }
  94655. if ($token->equals($endEdge)) {
  94656. --$blockLevel;
  94657. if (0 === $blockLevel) {
  94658. break;
  94659. }
  94660. }
  94661. }
  94662. if (!$this[$index]->equals($endEdge)) {
  94663. throw new \UnexpectedValueException(\sprintf('Missing block "%s".', $findEnd ? 'end' : 'start'));
  94664. }
  94665. if ($startIndex < $index) {
  94666. $this->blockStartCache[$startIndex] = $index;
  94667. $this->blockEndCache[$index] = $startIndex;
  94668. } else {
  94669. $this->blockStartCache[$index] = $startIndex;
  94670. $this->blockEndCache[$startIndex] = $index;
  94671. }
  94672. return $index;
  94673. }
  94674. private static function calculateHash(string $code): string
  94675. {
  94676. return Hasher::calculate($code);
  94677. }
  94678. private static function getCache(string $key): self
  94679. {
  94680. if (!self::hasCache($key)) {
  94681. throw new \OutOfBoundsException(\sprintf('Unknown cache key: "%s".', $key));
  94682. }
  94683. return self::$cache[$key];
  94684. }
  94685. private static function hasCache(string $key): bool
  94686. {
  94687. return isset(self::$cache[$key]);
  94688. }
  94689. private static function setCache(string $key, self $value): void
  94690. {
  94691. self::$cache[$key] = $value;
  94692. }
  94693. private function changeCodeHash(string $codeHash): void
  94694. {
  94695. if (null !== $this->codeHash) {
  94696. self::clearCache($this->codeHash);
  94697. }
  94698. $this->codeHash = $codeHash;
  94699. self::setCache($this->codeHash, $this);
  94700. }
  94701. private function registerFoundToken(Token $token): void
  94702. {
  94703. $tokenKind = $token->isArray() ? $token->getId() : $token->getContent();
  94704. $this->foundTokenKinds[$tokenKind] ??= 0;
  94705. ++$this->foundTokenKinds[$tokenKind];
  94706. }
  94707. private function unregisterFoundToken(Token $token): void
  94708. {
  94709. $tokenKind = $token->isArray() ? $token->getId() : $token->getContent();
  94710. \assert(($this->foundTokenKinds[$tokenKind] ?? 0) > 0);
  94711. --$this->foundTokenKinds[$tokenKind];
  94712. }
  94713. private function extractTokenKind($token)
  94714. {
  94715. return $token instanceof Token
  94716. ? ($token->isArray() ? $token->getId() : $token->getContent())
  94717. : (\is_array($token) ? $token[0] : $token);
  94718. }
  94719. private function getTokenNotOfKind(int $index, int $direction, callable $filter): ?int
  94720. {
  94721. while (true) {
  94722. $index += $direction;
  94723. if (!$this->offsetExists($index)) {
  94724. return null;
  94725. }
  94726. if ($this->isEmptyAt($index) || $filter($index)) {
  94727. continue;
  94728. }
  94729. return $index;
  94730. }
  94731. }
  94732. private static function isKeyCaseSensitive($caseSensitive, int $key): bool
  94733. {
  94734. if (\is_array($caseSensitive)) {
  94735. return $caseSensitive[$key] ?? true;
  94736. }
  94737. return $caseSensitive;
  94738. }
  94739. }
  94740. <?php
  94741. declare(strict_types=1);
  94742. namespace PhpCsFixer\Tokenizer;
  94743. use PhpCsFixer\Utils;
  94744. /**
  94745. @readonly
  94746. */
  94747. final class Token
  94748. {
  94749. private string $content;
  94750. private ?int $id;
  94751. private bool $isArray;
  94752. public function __construct($token)
  94753. {
  94754. if (\is_array($token)) {
  94755. if (!\is_int($token[0])) {
  94756. throw new \InvalidArgumentException(\sprintf(
  94757. 'Id must be an int, got "%s".',
  94758. get_debug_type($token[0])
  94759. ));
  94760. }
  94761. if (!\is_string($token[1])) {
  94762. throw new \InvalidArgumentException(\sprintf(
  94763. 'Content must be a string, got "%s".',
  94764. get_debug_type($token[1])
  94765. ));
  94766. }
  94767. if ('' === $token[1]) {
  94768. throw new \InvalidArgumentException('Cannot set empty content for id-based Token.');
  94769. }
  94770. $this->isArray = true;
  94771. $this->id = $token[0];
  94772. $this->content = $token[1];
  94773. } elseif (\is_string($token)) {
  94774. $this->isArray = false;
  94775. $this->id = null;
  94776. $this->content = $token;
  94777. } else {
  94778. throw new \InvalidArgumentException(\sprintf('Cannot recognize input value as valid Token prototype, got "%s".', get_debug_type($token)));
  94779. }
  94780. }
  94781. public static function getCastTokenKinds(): array
  94782. {
  94783. static $castTokens = [T_ARRAY_CAST, T_BOOL_CAST, T_DOUBLE_CAST, T_INT_CAST, T_OBJECT_CAST, T_STRING_CAST, T_UNSET_CAST];
  94784. return $castTokens;
  94785. }
  94786. public static function getClassyTokenKinds(): array
  94787. {
  94788. static $classTokens = [T_CLASS, T_TRAIT, T_INTERFACE, FCT::T_ENUM];
  94789. return $classTokens;
  94790. }
  94791. public static function getObjectOperatorKinds(): array
  94792. {
  94793. static $objectOperators = [T_OBJECT_OPERATOR, FCT::T_NULLSAFE_OBJECT_OPERATOR];
  94794. return $objectOperators;
  94795. }
  94796. public function equals($other, bool $caseSensitive = true): bool
  94797. {
  94798. if ('&' === $other) {
  94799. return '&' === $this->content && (null === $this->id || $this->isGivenKind([FCT::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, FCT::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG]));
  94800. }
  94801. if (null === $this->id && '&' === $this->content) {
  94802. return $other instanceof self && '&' === $other->content && (null === $other->id || $other->isGivenKind([FCT::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, FCT::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG]));
  94803. }
  94804. if ($other instanceof self) {
  94805. if (!$other->isArray) {
  94806. $otherPrototype = $other->content;
  94807. } else {
  94808. $otherPrototype = [
  94809. $other->id,
  94810. $other->content,
  94811. ];
  94812. }
  94813. } else {
  94814. $otherPrototype = $other;
  94815. }
  94816. if ($this->isArray !== \is_array($otherPrototype)) {
  94817. return false;
  94818. }
  94819. if (!$this->isArray) {
  94820. return $this->content === $otherPrototype;
  94821. }
  94822. if ($this->id !== $otherPrototype[0]) {
  94823. return false;
  94824. }
  94825. if (isset($otherPrototype[1])) {
  94826. if ($caseSensitive) {
  94827. if ($this->content !== $otherPrototype[1]) {
  94828. return false;
  94829. }
  94830. } elseif (0 !== strcasecmp($this->content, $otherPrototype[1])) {
  94831. return false;
  94832. }
  94833. }
  94834. unset($otherPrototype[0], $otherPrototype[1]);
  94835. return [] === $otherPrototype;
  94836. }
  94837. public function equalsAny(array $others, bool $caseSensitive = true): bool
  94838. {
  94839. foreach ($others as $other) {
  94840. if ($this->equals($other, $caseSensitive)) {
  94841. return true;
  94842. }
  94843. }
  94844. return false;
  94845. }
  94846. public static function isKeyCaseSensitive($caseSensitive, int $key): bool
  94847. {
  94848. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  94849. 'Method "%s" is deprecated and will be removed in the next major version.',
  94850. __METHOD__
  94851. )));
  94852. if (\is_array($caseSensitive)) {
  94853. return $caseSensitive[$key] ?? true;
  94854. }
  94855. return $caseSensitive;
  94856. }
  94857. public function getPrototype()
  94858. {
  94859. if (!$this->isArray) {
  94860. return $this->content;
  94861. }
  94862. \assert('' !== $this->content);
  94863. return [
  94864. $this->id,
  94865. $this->content,
  94866. ];
  94867. }
  94868. public function getContent(): string
  94869. {
  94870. return $this->content;
  94871. }
  94872. public function getId(): ?int
  94873. {
  94874. return $this->id;
  94875. }
  94876. public function getName(): ?string
  94877. {
  94878. if (null === $this->id) {
  94879. return null;
  94880. }
  94881. return self::getNameForId($this->id);
  94882. }
  94883. public static function getNameForId(int $id): ?string
  94884. {
  94885. if (CT::has($id)) {
  94886. return CT::getName($id);
  94887. }
  94888. $name = token_name($id);
  94889. return 'UNKNOWN' === $name ? null : $name;
  94890. }
  94891. public static function getKeywords(): array
  94892. {
  94893. static $keywords = null;
  94894. if (null === $keywords) {
  94895. $keywords = self::getTokenKindsForNames(['T_ABSTRACT', 'T_ARRAY', 'T_AS', 'T_BREAK', 'T_CALLABLE', 'T_CASE',
  94896. 'T_CATCH', 'T_CLASS', 'T_CLONE', 'T_CONST', 'T_CONTINUE', 'T_DECLARE', 'T_DEFAULT', 'T_DO',
  94897. 'T_ECHO', 'T_ELSE', 'T_ELSEIF', 'T_EMPTY', 'T_ENDDECLARE', 'T_ENDFOR', 'T_ENDFOREACH',
  94898. 'T_ENDIF', 'T_ENDSWITCH', 'T_ENDWHILE', 'T_EVAL', 'T_EXIT', 'T_EXTENDS', 'T_FINAL',
  94899. 'T_FINALLY', 'T_FN', 'T_FOR', 'T_FOREACH', 'T_FUNCTION', 'T_GLOBAL', 'T_GOTO', 'T_HALT_COMPILER',
  94900. 'T_IF', 'T_IMPLEMENTS', 'T_INCLUDE', 'T_INCLUDE_ONCE', 'T_INSTANCEOF', 'T_INSTEADOF',
  94901. 'T_INTERFACE', 'T_ISSET', 'T_LIST', 'T_LOGICAL_AND', 'T_LOGICAL_OR', 'T_LOGICAL_XOR',
  94902. 'T_NAMESPACE', 'T_NEW', 'T_PRINT', 'T_PRIVATE', 'T_PROTECTED', 'T_PUBLIC', 'T_REQUIRE',
  94903. 'T_REQUIRE_ONCE', 'T_RETURN', 'T_STATIC', 'T_SWITCH', 'T_THROW', 'T_TRAIT', 'T_TRY',
  94904. 'T_UNSET', 'T_USE', 'T_VAR', 'T_WHILE', 'T_YIELD', 'T_YIELD_FROM',
  94905. ]) + [
  94906. CT::T_ARRAY_TYPEHINT => CT::T_ARRAY_TYPEHINT,
  94907. CT::T_CLASS_CONSTANT => CT::T_CLASS_CONSTANT,
  94908. CT::T_CONST_IMPORT => CT::T_CONST_IMPORT,
  94909. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE => CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  94910. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED => CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  94911. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC => CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  94912. CT::T_FUNCTION_IMPORT => CT::T_FUNCTION_IMPORT,
  94913. CT::T_NAMESPACE_OPERATOR => CT::T_NAMESPACE_OPERATOR,
  94914. CT::T_USE_LAMBDA => CT::T_USE_LAMBDA,
  94915. CT::T_USE_TRAIT => CT::T_USE_TRAIT,
  94916. FCT::T_ENUM => FCT::T_ENUM,
  94917. FCT::T_MATCH => FCT::T_MATCH,
  94918. FCT::T_PRIVATE_SET => FCT::T_PRIVATE_SET,
  94919. FCT::T_PROTECTED_SET => FCT::T_PROTECTED_SET,
  94920. FCT::T_PUBLIC_SET => FCT::T_PUBLIC_SET,
  94921. FCT::T_READONLY => FCT::T_READONLY,
  94922. ];
  94923. }
  94924. return $keywords;
  94925. }
  94926. public static function getMagicConstants(): array
  94927. {
  94928. static $magicConstants = null;
  94929. if (null === $magicConstants) {
  94930. $magicConstants = self::getTokenKindsForNames(['T_CLASS_C', 'T_DIR', 'T_FILE', 'T_FUNC_C', 'T_LINE', 'T_METHOD_C', 'T_NS_C', 'T_TRAIT_C']);
  94931. }
  94932. return $magicConstants;
  94933. }
  94934. /**
  94935. @phpstan-assert-if-true
  94936. @phpstan-assert-if-true
  94937. */
  94938. public function isArray(): bool
  94939. {
  94940. return $this->isArray;
  94941. }
  94942. /**
  94943. @phpstan-assert-if-true
  94944. */
  94945. public function isCast(): bool
  94946. {
  94947. return $this->isGivenKind(self::getCastTokenKinds());
  94948. }
  94949. /**
  94950. @phpstan-assert-if-true
  94951. */
  94952. public function isClassy(): bool
  94953. {
  94954. return $this->isGivenKind(self::getClassyTokenKinds());
  94955. }
  94956. /**
  94957. @phpstan-assert-if-true
  94958. */
  94959. public function isComment(): bool
  94960. {
  94961. static $commentTokens = [T_COMMENT, T_DOC_COMMENT];
  94962. return $this->isGivenKind($commentTokens);
  94963. }
  94964. /**
  94965. @phpstan-assert-if-true
  94966. */
  94967. public function isObjectOperator(): bool
  94968. {
  94969. return $this->isGivenKind(self::getObjectOperatorKinds());
  94970. }
  94971. /**
  94972. @phpstan-assert-if-true
  94973. */
  94974. public function isGivenKind($possibleKind): bool
  94975. {
  94976. return $this->isArray && (\is_array($possibleKind) ? \in_array($this->id, $possibleKind, true) : $this->id === $possibleKind);
  94977. }
  94978. /**
  94979. @phpstan-assert-if-true
  94980. */
  94981. public function isKeyword(): bool
  94982. {
  94983. $keywords = self::getKeywords();
  94984. return $this->isArray && isset($keywords[$this->id]);
  94985. }
  94986. /**
  94987. @phpstan-assert-if-true
  94988. */
  94989. public function isNativeConstant(): bool
  94990. {
  94991. static $nativeConstantStrings = ['true', 'false', 'null'];
  94992. return $this->isArray && \in_array(strtolower($this->content), $nativeConstantStrings, true);
  94993. }
  94994. /**
  94995. @phpstan-assert-if-true
  94996. */
  94997. public function isMagicConstant(): bool
  94998. {
  94999. $magicConstants = self::getMagicConstants();
  95000. return $this->isArray && isset($magicConstants[$this->id]);
  95001. }
  95002. public function isWhitespace(?string $whitespaces = " \t\n\r\0\x0B"): bool
  95003. {
  95004. if (null === $whitespaces) {
  95005. $whitespaces = " \t\n\r\0\x0B";
  95006. }
  95007. if ($this->isArray && !$this->isGivenKind(T_WHITESPACE)) {
  95008. return false;
  95009. }
  95010. return '' === trim($this->content, $whitespaces);
  95011. }
  95012. public function toArray(): array
  95013. {
  95014. return [
  95015. 'id' => $this->id,
  95016. 'name' => $this->getName(),
  95017. 'content' => $this->content,
  95018. 'isArray' => $this->isArray,
  95019. 'changed' => false,
  95020. ];
  95021. }
  95022. public function toJson(): string
  95023. {
  95024. $jsonResult = json_encode($this->toArray(), JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
  95025. if (JSON_ERROR_NONE !== json_last_error()) {
  95026. $jsonResult = json_encode(
  95027. [
  95028. 'errorDescription' => 'Cannot encode Tokens to JSON.',
  95029. 'rawErrorMessage' => json_last_error_msg(),
  95030. ],
  95031. JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK
  95032. );
  95033. }
  95034. \assert(false !== $jsonResult);
  95035. return $jsonResult;
  95036. }
  95037. private static function getTokenKindsForNames(array $tokenNames): array
  95038. {
  95039. $keywords = [];
  95040. foreach ($tokenNames as $keywordName) {
  95041. $keyword = \constant($keywordName);
  95042. $keywords[$keyword] = $keyword;
  95043. }
  95044. return $keywords;
  95045. }
  95046. }
  95047. <?php
  95048. declare(strict_types=1);
  95049. namespace PhpCsFixer\Tokenizer;
  95050. final class FCT
  95051. {
  95052. public const T_ATTRIBUTE = \PHP_VERSION_ID >= 8_00_00 ? T_ATTRIBUTE : -801;
  95053. public const T_MATCH = \PHP_VERSION_ID >= 8_00_00 ? T_MATCH : -802;
  95054. public const T_NULLSAFE_OBJECT_OPERATOR = \PHP_VERSION_ID >= 8_00_00 ? T_NULLSAFE_OBJECT_OPERATOR : -803;
  95055. public const T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG = \PHP_VERSION_ID >= 8_01_00 ? T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG : -811;
  95056. public const T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG = \PHP_VERSION_ID >= 8_01_00 ? T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG : -812;
  95057. public const T_ENUM = \PHP_VERSION_ID >= 8_01_00 ? T_ENUM : -813;
  95058. public const T_READONLY = \PHP_VERSION_ID >= 8_01_00 ? T_READONLY : -814;
  95059. public const T_PRIVATE_SET = \PHP_VERSION_ID >= 8_04_00 ? T_PRIVATE_SET : -841;
  95060. public const T_PROTECTED_SET = \PHP_VERSION_ID >= 8_04_00 ? T_PROTECTED_SET : -842;
  95061. public const T_PUBLIC_SET = \PHP_VERSION_ID >= 8_04_00 ? T_PUBLIC_SET : -843;
  95062. public const T_PROPERTY_C = \PHP_VERSION_ID >= 8_04_00 ? T_PROPERTY_C : -844;
  95063. }
  95064. <?php
  95065. declare(strict_types=1);
  95066. namespace PhpCsFixer\Tokenizer\Transformer;
  95067. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95068. use PhpCsFixer\Tokenizer\Processor\ImportProcessor;
  95069. use PhpCsFixer\Tokenizer\Token;
  95070. use PhpCsFixer\Tokenizer\Tokens;
  95071. final class NameQualifiedTransformer extends AbstractTransformer
  95072. {
  95073. public function getPriority(): int
  95074. {
  95075. return 1;
  95076. }
  95077. public function getRequiredPhpVersionId(): int
  95078. {
  95079. return 8_00_00;
  95080. }
  95081. public function process(Tokens $tokens, Token $token, int $index): void
  95082. {
  95083. if ($token->isGivenKind([T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED])) {
  95084. $this->transformQualified($tokens, $token, $index);
  95085. } elseif ($token->isGivenKind(T_NAME_RELATIVE)) {
  95086. $this->transformRelative($tokens, $token, $index);
  95087. }
  95088. }
  95089. public function getCustomTokens(): array
  95090. {
  95091. return [];
  95092. }
  95093. private function transformQualified(Tokens $tokens, Token $token, int $index): void
  95094. {
  95095. $newTokens = ImportProcessor::tokenizeName($token->getContent());
  95096. $tokens->overrideRange($index, $index, $newTokens);
  95097. }
  95098. private function transformRelative(Tokens $tokens, Token $token, int $index): void
  95099. {
  95100. $newTokens = ImportProcessor::tokenizeName($token->getContent());
  95101. $newTokens[0] = new Token([T_NAMESPACE, 'namespace']);
  95102. $tokens->overrideRange($index, $index, $newTokens);
  95103. }
  95104. }
  95105. <?php
  95106. declare(strict_types=1);
  95107. namespace PhpCsFixer\Tokenizer\Transformer;
  95108. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95109. use PhpCsFixer\Tokenizer\CT;
  95110. use PhpCsFixer\Tokenizer\Token;
  95111. use PhpCsFixer\Tokenizer\Tokens;
  95112. final class ArrayTypehintTransformer extends AbstractTransformer
  95113. {
  95114. public function getRequiredPhpVersionId(): int
  95115. {
  95116. return 5_00_00;
  95117. }
  95118. public function process(Tokens $tokens, Token $token, int $index): void
  95119. {
  95120. if (!$token->isGivenKind(T_ARRAY)) {
  95121. return;
  95122. }
  95123. $nextIndex = $tokens->getNextMeaningfulToken($index);
  95124. $nextToken = $tokens[$nextIndex];
  95125. if (!$nextToken->equals('(')) {
  95126. $tokens[$index] = new Token([CT::T_ARRAY_TYPEHINT, $token->getContent()]);
  95127. }
  95128. }
  95129. public function getCustomTokens(): array
  95130. {
  95131. return [CT::T_ARRAY_TYPEHINT];
  95132. }
  95133. }
  95134. <?php
  95135. declare(strict_types=1);
  95136. namespace PhpCsFixer\Tokenizer\Transformer;
  95137. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95138. use PhpCsFixer\Tokenizer\CT;
  95139. use PhpCsFixer\Tokenizer\Token;
  95140. use PhpCsFixer\Tokenizer\Tokens;
  95141. final class ImportTransformer extends AbstractTransformer
  95142. {
  95143. public function getPriority(): int
  95144. {
  95145. return -1;
  95146. }
  95147. public function getRequiredPhpVersionId(): int
  95148. {
  95149. return 5_06_00;
  95150. }
  95151. public function process(Tokens $tokens, Token $token, int $index): void
  95152. {
  95153. if (!$token->isGivenKind([T_CONST, T_FUNCTION])) {
  95154. return;
  95155. }
  95156. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  95157. if (!$prevToken->isGivenKind(T_USE)) {
  95158. $nextToken = $tokens[$tokens->getNextTokenOfKind($index, ['=', '(', [CT::T_RETURN_REF], [CT::T_GROUP_IMPORT_BRACE_CLOSE]])];
  95159. if (!$nextToken->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  95160. return;
  95161. }
  95162. }
  95163. $tokens[$index] = new Token([
  95164. $token->isGivenKind(T_FUNCTION) ? CT::T_FUNCTION_IMPORT : CT::T_CONST_IMPORT,
  95165. $token->getContent(),
  95166. ]);
  95167. }
  95168. public function getCustomTokens(): array
  95169. {
  95170. return [CT::T_CONST_IMPORT, CT::T_FUNCTION_IMPORT];
  95171. }
  95172. }
  95173. <?php
  95174. declare(strict_types=1);
  95175. namespace PhpCsFixer\Tokenizer\Transformer;
  95176. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95177. use PhpCsFixer\Tokenizer\CT;
  95178. use PhpCsFixer\Tokenizer\Token;
  95179. use PhpCsFixer\Tokenizer\Tokens;
  95180. final class SquareBraceTransformer extends AbstractTransformer
  95181. {
  95182. public function getPriority(): int
  95183. {
  95184. return -1;
  95185. }
  95186. public function getRequiredPhpVersionId(): int
  95187. {
  95188. return 5_00_00;
  95189. }
  95190. public function process(Tokens $tokens, Token $token, int $index): void
  95191. {
  95192. if ($this->isArrayDestructing($tokens, $index)) {
  95193. $this->transformIntoDestructuringSquareBrace($tokens, $index);
  95194. return;
  95195. }
  95196. if ($this->isShortArray($tokens, $index)) {
  95197. $this->transformIntoArraySquareBrace($tokens, $index);
  95198. }
  95199. }
  95200. public function getCustomTokens(): array
  95201. {
  95202. return [
  95203. CT::T_ARRAY_SQUARE_BRACE_OPEN,
  95204. CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  95205. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  95206. CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  95207. ];
  95208. }
  95209. private function transformIntoArraySquareBrace(Tokens $tokens, int $index): void
  95210. {
  95211. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  95212. $tokens[$index] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
  95213. $tokens[$endIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);
  95214. }
  95215. private function transformIntoDestructuringSquareBrace(Tokens $tokens, int $index): void
  95216. {
  95217. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);
  95218. $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  95219. $tokens[$endIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  95220. $previousMeaningfulIndex = $index;
  95221. $index = $tokens->getNextMeaningfulToken($index);
  95222. while ($index < $endIndex) {
  95223. if ($tokens[$index]->equals('[') && $tokens[$previousMeaningfulIndex]->equalsAny([[CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN], ','])) {
  95224. $tokens[$tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index)] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
  95225. $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
  95226. }
  95227. $previousMeaningfulIndex = $index;
  95228. $index = $tokens->getNextMeaningfulToken($index);
  95229. }
  95230. }
  95231. private function isShortArray(Tokens $tokens, int $index): bool
  95232. {
  95233. if (!$tokens[$index]->equals('[')) {
  95234. return false;
  95235. }
  95236. static $disallowedPrevTokens = [
  95237. ')',
  95238. ']',
  95239. '}',
  95240. '"',
  95241. [T_CONSTANT_ENCAPSED_STRING],
  95242. [T_STRING],
  95243. [T_STRING_VARNAME],
  95244. [T_VARIABLE],
  95245. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  95246. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  95247. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  95248. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  95249. ];
  95250. $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
  95251. if ($prevToken->equalsAny($disallowedPrevTokens)) {
  95252. return false;
  95253. }
  95254. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  95255. if ($nextToken->equals(']')) {
  95256. return true;
  95257. }
  95258. return !$this->isArrayDestructing($tokens, $index);
  95259. }
  95260. private function isArrayDestructing(Tokens $tokens, int $index): bool
  95261. {
  95262. if (!$tokens[$index]->equals('[')) {
  95263. return false;
  95264. }
  95265. static $disallowedPrevTokens = [
  95266. ')',
  95267. ']',
  95268. '"',
  95269. [T_CONSTANT_ENCAPSED_STRING],
  95270. [T_STRING],
  95271. [T_STRING_VARNAME],
  95272. [T_VARIABLE],
  95273. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  95274. [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
  95275. [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
  95276. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  95277. ];
  95278. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  95279. $prevToken = $tokens[$prevIndex];
  95280. if ($prevToken->equalsAny($disallowedPrevTokens)) {
  95281. return false;
  95282. }
  95283. if ($prevToken->isGivenKind(T_AS)) {
  95284. return true;
  95285. }
  95286. if ($prevToken->isGivenKind(T_DOUBLE_ARROW)) {
  95287. $variableIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  95288. if (!$tokens[$variableIndex]->isGivenKind(T_VARIABLE)) {
  95289. return false;
  95290. }
  95291. $prevVariableIndex = $tokens->getPrevMeaningfulToken($variableIndex);
  95292. if ($tokens[$prevVariableIndex]->isGivenKind(T_AS)) {
  95293. return true;
  95294. }
  95295. }
  95296. $type = Tokens::detectBlockType($tokens[$index]);
  95297. $end = $tokens->findBlockEnd($type['type'], $index);
  95298. $nextToken = $tokens[$tokens->getNextMeaningfulToken($end)];
  95299. return $nextToken->equals('=');
  95300. }
  95301. }
  95302. <?php
  95303. declare(strict_types=1);
  95304. namespace PhpCsFixer\Tokenizer\Transformer;
  95305. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95306. use PhpCsFixer\Tokenizer\CT;
  95307. use PhpCsFixer\Tokenizer\FCT;
  95308. use PhpCsFixer\Tokenizer\Token;
  95309. use PhpCsFixer\Tokenizer\Tokens;
  95310. final class TypeColonTransformer extends AbstractTransformer
  95311. {
  95312. public function getPriority(): int
  95313. {
  95314. return -10;
  95315. }
  95316. public function getRequiredPhpVersionId(): int
  95317. {
  95318. return 7_00_00;
  95319. }
  95320. public function process(Tokens $tokens, Token $token, int $index): void
  95321. {
  95322. if (!$token->equals(':')) {
  95323. return;
  95324. }
  95325. $endIndex = $tokens->getPrevMeaningfulToken($index);
  95326. if ($tokens[$tokens->getPrevMeaningfulToken($endIndex)]->isGivenKind(FCT::T_ENUM)) {
  95327. $tokens[$index] = new Token([CT::T_TYPE_COLON, ':']);
  95328. return;
  95329. }
  95330. if (!$tokens[$endIndex]->equals(')')) {
  95331. return;
  95332. }
  95333. $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex);
  95334. $prevIndex = $tokens->getPrevMeaningfulToken($startIndex);
  95335. $prevToken = $tokens[$prevIndex];
  95336. if ($prevToken->isGivenKind(T_STRING)) {
  95337. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  95338. $prevToken = $tokens[$prevIndex];
  95339. }
  95340. if ($prevToken->isGivenKind([T_FUNCTION, CT::T_RETURN_REF, CT::T_USE_LAMBDA, T_FN])) {
  95341. $tokens[$index] = new Token([CT::T_TYPE_COLON, ':']);
  95342. }
  95343. }
  95344. public function getCustomTokens(): array
  95345. {
  95346. return [CT::T_TYPE_COLON];
  95347. }
  95348. }
  95349. <?php
  95350. declare(strict_types=1);
  95351. namespace PhpCsFixer\Tokenizer\Transformer;
  95352. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95353. use PhpCsFixer\Tokenizer\CT;
  95354. use PhpCsFixer\Tokenizer\Token;
  95355. use PhpCsFixer\Tokenizer\Tokens;
  95356. final class ReturnRefTransformer extends AbstractTransformer
  95357. {
  95358. public function getRequiredPhpVersionId(): int
  95359. {
  95360. return 5_00_00;
  95361. }
  95362. public function process(Tokens $tokens, Token $token, int $index): void
  95363. {
  95364. if ($token->equals('&') && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind([T_FUNCTION, T_FN])) {
  95365. $tokens[$index] = new Token([CT::T_RETURN_REF, '&']);
  95366. }
  95367. }
  95368. public function getCustomTokens(): array
  95369. {
  95370. return [CT::T_RETURN_REF];
  95371. }
  95372. }
  95373. <?php
  95374. declare(strict_types=1);
  95375. namespace PhpCsFixer\Tokenizer\Transformer;
  95376. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95377. use PhpCsFixer\Tokenizer\Token;
  95378. use PhpCsFixer\Tokenizer\Tokens;
  95379. final class WhitespacyCommentTransformer extends AbstractTransformer
  95380. {
  95381. public function getRequiredPhpVersionId(): int
  95382. {
  95383. return 5_00_00;
  95384. }
  95385. public function process(Tokens $tokens, Token $token, int $index): void
  95386. {
  95387. if (!$token->isComment()) {
  95388. return;
  95389. }
  95390. $content = $token->getContent();
  95391. $trimmedContent = rtrim($content);
  95392. if ($content === $trimmedContent) {
  95393. return;
  95394. }
  95395. $whitespaces = substr($content, \strlen($trimmedContent));
  95396. $tokens[$index] = new Token([$token->getId(), $trimmedContent]);
  95397. if (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
  95398. $tokens[$index + 1] = new Token([T_WHITESPACE, $whitespaces.$tokens[$index + 1]->getContent()]);
  95399. } else {
  95400. $tokens->insertAt($index + 1, new Token([T_WHITESPACE, $whitespaces]));
  95401. }
  95402. }
  95403. public function getCustomTokens(): array
  95404. {
  95405. return [];
  95406. }
  95407. }
  95408. <?php
  95409. declare(strict_types=1);
  95410. namespace PhpCsFixer\Tokenizer\Transformer;
  95411. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95412. use PhpCsFixer\Tokenizer\CT;
  95413. use PhpCsFixer\Tokenizer\Token;
  95414. use PhpCsFixer\Tokenizer\Tokens;
  95415. final class FirstClassCallableTransformer extends AbstractTransformer
  95416. {
  95417. public function getRequiredPhpVersionId(): int
  95418. {
  95419. return 8_01_00;
  95420. }
  95421. public function process(Tokens $tokens, Token $token, int $index): void
  95422. {
  95423. if (
  95424. $token->isGivenKind(T_ELLIPSIS)
  95425. && $tokens[$tokens->getPrevMeaningfulToken($index)]->equals('(')
  95426. && $tokens[$tokens->getNextMeaningfulToken($index)]->equals(')')
  95427. ) {
  95428. $tokens[$index] = new Token([CT::T_FIRST_CLASS_CALLABLE, '...']);
  95429. }
  95430. }
  95431. public function getCustomTokens(): array
  95432. {
  95433. return [
  95434. CT::T_FIRST_CLASS_CALLABLE,
  95435. ];
  95436. }
  95437. }
  95438. <?php
  95439. declare(strict_types=1);
  95440. namespace PhpCsFixer\Tokenizer\Transformer;
  95441. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95442. use PhpCsFixer\Tokenizer\CT;
  95443. use PhpCsFixer\Tokenizer\Token;
  95444. use PhpCsFixer\Tokenizer\Tokens;
  95445. final class NamespaceOperatorTransformer extends AbstractTransformer
  95446. {
  95447. public function getRequiredPhpVersionId(): int
  95448. {
  95449. return 5_03_00;
  95450. }
  95451. public function process(Tokens $tokens, Token $token, int $index): void
  95452. {
  95453. if (!$token->isGivenKind(T_NAMESPACE)) {
  95454. return;
  95455. }
  95456. $nextIndex = $tokens->getNextMeaningfulToken($index);
  95457. if ($tokens[$nextIndex]->isGivenKind(T_NS_SEPARATOR)) {
  95458. $tokens[$index] = new Token([CT::T_NAMESPACE_OPERATOR, $token->getContent()]);
  95459. }
  95460. }
  95461. public function getCustomTokens(): array
  95462. {
  95463. return [CT::T_NAMESPACE_OPERATOR];
  95464. }
  95465. }
  95466. <?php
  95467. declare(strict_types=1);
  95468. namespace PhpCsFixer\Tokenizer\Transformer;
  95469. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95470. use PhpCsFixer\Tokenizer\CT;
  95471. use PhpCsFixer\Tokenizer\FCT;
  95472. use PhpCsFixer\Tokenizer\Token;
  95473. use PhpCsFixer\Tokenizer\Tokens;
  95474. final class BraceTransformer extends AbstractTransformer
  95475. {
  95476. public function getRequiredPhpVersionId(): int
  95477. {
  95478. return 5_00_00;
  95479. }
  95480. public function process(Tokens $tokens, Token $token, int $index): void
  95481. {
  95482. $this->transformIntoCurlyCloseBrace($tokens, $index);
  95483. $this->transformIntoDollarCloseBrace($tokens, $index);
  95484. $this->transformIntoDynamicPropBraces($tokens, $index);
  95485. $this->transformIntoDynamicVarBraces($tokens, $index);
  95486. $this->transformIntoPropertyHookBraces($tokens, $index);
  95487. $this->transformIntoCurlyIndexBraces($tokens, $index);
  95488. $this->transformIntoGroupUseBraces($tokens, $index);
  95489. $this->transformIntoDynamicClassConstantFetchBraces($tokens, $index);
  95490. }
  95491. public function getCustomTokens(): array
  95492. {
  95493. return [
  95494. CT::T_CURLY_CLOSE,
  95495. CT::T_DOLLAR_CLOSE_CURLY_BRACES,
  95496. CT::T_DYNAMIC_PROP_BRACE_OPEN,
  95497. CT::T_DYNAMIC_PROP_BRACE_CLOSE,
  95498. CT::T_DYNAMIC_VAR_BRACE_OPEN,
  95499. CT::T_DYNAMIC_VAR_BRACE_CLOSE,
  95500. CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
  95501. CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
  95502. CT::T_GROUP_IMPORT_BRACE_OPEN,
  95503. CT::T_GROUP_IMPORT_BRACE_CLOSE,
  95504. CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
  95505. CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
  95506. CT::T_PROPERTY_HOOK_BRACE_OPEN,
  95507. CT::T_PROPERTY_HOOK_BRACE_CLOSE,
  95508. ];
  95509. }
  95510. private function transformIntoCurlyCloseBrace(Tokens $tokens, int $index): void
  95511. {
  95512. $token = $tokens[$index];
  95513. if (!$token->isGivenKind(T_CURLY_OPEN)) {
  95514. return;
  95515. }
  95516. $level = 1;
  95517. do {
  95518. ++$index;
  95519. if ($tokens[$index]->equals('{') || $tokens[$index]->isGivenKind(T_CURLY_OPEN)) {
  95520. ++$level;
  95521. } elseif ($tokens[$index]->equals('}')) {
  95522. --$level;
  95523. }
  95524. } while (0 < $level);
  95525. $tokens[$index] = new Token([CT::T_CURLY_CLOSE, '}']);
  95526. }
  95527. private function transformIntoDollarCloseBrace(Tokens $tokens, int $index): void
  95528. {
  95529. $token = $tokens[$index];
  95530. if ($token->isGivenKind(T_DOLLAR_OPEN_CURLY_BRACES)) {
  95531. $nextIndex = $tokens->getNextTokenOfKind($index, ['}']);
  95532. $tokens[$nextIndex] = new Token([CT::T_DOLLAR_CLOSE_CURLY_BRACES, '}']);
  95533. }
  95534. }
  95535. private function transformIntoDynamicPropBraces(Tokens $tokens, int $index): void
  95536. {
  95537. $token = $tokens[$index];
  95538. if (!$token->isObjectOperator()) {
  95539. return;
  95540. }
  95541. if (!$tokens[$index + 1]->equals('{')) {
  95542. return;
  95543. }
  95544. $openIndex = $index + 1;
  95545. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $openIndex);
  95546. $tokens[$openIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_OPEN, '{']);
  95547. $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_CLOSE, '}']);
  95548. }
  95549. private function transformIntoDynamicVarBraces(Tokens $tokens, int $index): void
  95550. {
  95551. $token = $tokens[$index];
  95552. if (!$token->equals('$')) {
  95553. return;
  95554. }
  95555. $openIndex = $tokens->getNextMeaningfulToken($index);
  95556. if (null === $openIndex) {
  95557. return;
  95558. }
  95559. $openToken = $tokens[$openIndex];
  95560. if (!$openToken->equals('{')) {
  95561. return;
  95562. }
  95563. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $openIndex);
  95564. $tokens[$openIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_OPEN, '{']);
  95565. $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_CLOSE, '}']);
  95566. }
  95567. private function transformIntoPropertyHookBraces(Tokens $tokens, int $index): void
  95568. {
  95569. if (\PHP_VERSION_ID < 8_04_00) {
  95570. return;
  95571. }
  95572. $token = $tokens[$index];
  95573. if (!$token->equals('{')) {
  95574. return;
  95575. }
  95576. $nextIndex = $tokens->getNextMeaningfulToken($index);
  95577. while ($tokens[$nextIndex]->isGivenKind(FCT::T_ATTRIBUTE)) {
  95578. $nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $nextIndex);
  95579. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  95580. }
  95581. if (!$tokens[$nextIndex]->equalsAny([
  95582. [T_STRING, 'get'],
  95583. [T_STRING, 'set'],
  95584. ], false)) {
  95585. return;
  95586. }
  95587. $nextNextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  95588. if (!$tokens[$nextNextIndex]->equalsAny(['(', '{', ';', [T_DOUBLE_ARROW]])) {
  95589. return;
  95590. }
  95591. if ($tokens[$nextNextIndex]->equals('(')) {
  95592. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextNextIndex);
  95593. $afterCloseParenthesisIndex = $tokens->getNextMeaningfulToken($closeParenthesisIndex);
  95594. if (!$tokens[$afterCloseParenthesisIndex]->equalsAny(['{', [T_DOUBLE_ARROW]])) {
  95595. return;
  95596. }
  95597. }
  95598. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $index);
  95599. $tokens[$index] = new Token([CT::T_PROPERTY_HOOK_BRACE_OPEN, '{']);
  95600. $tokens[$closeIndex] = new Token([CT::T_PROPERTY_HOOK_BRACE_CLOSE, '}']);
  95601. }
  95602. private function transformIntoCurlyIndexBraces(Tokens $tokens, int $index): void
  95603. {
  95604. if (\PHP_VERSION_ID >= 8_04_00) {
  95605. return;
  95606. }
  95607. $token = $tokens[$index];
  95608. if (!$token->equals('{')) {
  95609. return;
  95610. }
  95611. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  95612. if (!$tokens[$prevIndex]->equalsAny([
  95613. [T_STRING],
  95614. [T_VARIABLE],
  95615. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  95616. ']',
  95617. ')',
  95618. ])) {
  95619. return;
  95620. }
  95621. if (
  95622. $tokens[$prevIndex]->isGivenKind(T_STRING)
  95623. && !$tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isObjectOperator()
  95624. ) {
  95625. return;
  95626. }
  95627. if (
  95628. $tokens[$prevIndex]->equals(')')
  95629. && !$tokens[$tokens->getPrevMeaningfulToken(
  95630. $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevIndex)
  95631. )]->isGivenKind(T_ARRAY)
  95632. ) {
  95633. return;
  95634. }
  95635. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $index);
  95636. $tokens[$index] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']);
  95637. $tokens[$closeIndex] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, '}']);
  95638. }
  95639. private function transformIntoGroupUseBraces(Tokens $tokens, int $index): void
  95640. {
  95641. $token = $tokens[$index];
  95642. if (!$token->equals('{')) {
  95643. return;
  95644. }
  95645. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  95646. if (!$tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  95647. return;
  95648. }
  95649. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $index);
  95650. $tokens[$index] = new Token([CT::T_GROUP_IMPORT_BRACE_OPEN, '{']);
  95651. $tokens[$closeIndex] = new Token([CT::T_GROUP_IMPORT_BRACE_CLOSE, '}']);
  95652. }
  95653. private function transformIntoDynamicClassConstantFetchBraces(Tokens $tokens, int $index): void
  95654. {
  95655. if (\PHP_VERSION_ID < 8_03_00) {
  95656. return;
  95657. }
  95658. $token = $tokens[$index];
  95659. if (!$token->equals('{')) {
  95660. return;
  95661. }
  95662. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($index);
  95663. while (!$tokens[$prevMeaningfulTokenIndex]->isGivenKind(T_DOUBLE_COLON)) {
  95664. if (!$tokens[$prevMeaningfulTokenIndex]->equals(')')) {
  95665. return;
  95666. }
  95667. $prevMeaningfulTokenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevMeaningfulTokenIndex);
  95668. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulTokenIndex);
  95669. if (!$tokens[$prevMeaningfulTokenIndex]->equals('}')) {
  95670. return;
  95671. }
  95672. $prevMeaningfulTokenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $prevMeaningfulTokenIndex);
  95673. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulTokenIndex);
  95674. }
  95675. $closeIndex = $this->naivelyFindCurlyBlockEnd($tokens, $index);
  95676. $nextMeaningfulTokenIndexAfterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
  95677. if (!$tokens[$nextMeaningfulTokenIndexAfterCloseIndex]->equalsAny([';', [T_CLOSE_TAG], [T_DOUBLE_COLON]])) {
  95678. return;
  95679. }
  95680. $tokens[$index] = new Token([CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN, '{']);
  95681. $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE, '}']);
  95682. }
  95683. private function naivelyFindCurlyBlockEnd(Tokens $tokens, int $startIndex): int
  95684. {
  95685. if (!$tokens->offsetExists($startIndex)) {
  95686. throw new \OutOfBoundsException(\sprintf('Unavailable index: "%s".', $startIndex));
  95687. }
  95688. if ('{' !== $tokens[$startIndex]->getContent()) {
  95689. throw new \InvalidArgumentException(\sprintf('Wrong start index: "%s".', $startIndex));
  95690. }
  95691. $blockLevel = 1;
  95692. $endIndex = $tokens->count() - 1;
  95693. for ($index = $startIndex + 1; $index !== $endIndex; ++$index) {
  95694. $token = $tokens[$index];
  95695. if ('{' === $token->getContent()) {
  95696. ++$blockLevel;
  95697. continue;
  95698. }
  95699. if ('}' === $token->getContent()) {
  95700. --$blockLevel;
  95701. if (0 === $blockLevel) {
  95702. if (!$token->equals('}')) {
  95703. throw new \UnexpectedValueException(\sprintf('Detected block end for index: "%s" was already transformed into other token type: "%s".', $startIndex, $token->getName()));
  95704. }
  95705. return $index;
  95706. }
  95707. }
  95708. }
  95709. throw new \UnexpectedValueException(\sprintf('Missing block end for index: "%s".', $startIndex));
  95710. }
  95711. }
  95712. <?php
  95713. declare(strict_types=1);
  95714. namespace PhpCsFixer\Tokenizer\Transformer;
  95715. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95716. use PhpCsFixer\Tokenizer\CT;
  95717. use PhpCsFixer\Tokenizer\FCT;
  95718. use PhpCsFixer\Tokenizer\Token;
  95719. use PhpCsFixer\Tokenizer\Tokens;
  95720. final class NullableTypeTransformer extends AbstractTransformer
  95721. {
  95722. private const TYPES = [
  95723. '(',
  95724. ',',
  95725. [CT::T_TYPE_COLON],
  95726. [CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC],
  95727. [CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED],
  95728. [CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE],
  95729. [CT::T_ATTRIBUTE_CLOSE],
  95730. [T_PRIVATE],
  95731. [T_PROTECTED],
  95732. [T_PUBLIC],
  95733. [T_VAR],
  95734. [T_STATIC],
  95735. [T_CONST],
  95736. [FCT::T_READONLY],
  95737. [FCT::T_PRIVATE_SET],
  95738. [FCT::T_PROTECTED_SET],
  95739. [FCT::T_PUBLIC_SET],
  95740. ];
  95741. public function getPriority(): int
  95742. {
  95743. return -20;
  95744. }
  95745. public function getRequiredPhpVersionId(): int
  95746. {
  95747. return 7_01_00;
  95748. }
  95749. public function process(Tokens $tokens, Token $token, int $index): void
  95750. {
  95751. if (!$token->equals('?')) {
  95752. return;
  95753. }
  95754. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  95755. if ($tokens[$prevIndex]->equalsAny(self::TYPES)) {
  95756. $tokens[$index] = new Token([CT::T_NULLABLE_TYPE, '?']);
  95757. }
  95758. }
  95759. public function getCustomTokens(): array
  95760. {
  95761. return [CT::T_NULLABLE_TYPE];
  95762. }
  95763. }
  95764. <?php
  95765. declare(strict_types=1);
  95766. namespace PhpCsFixer\Tokenizer\Transformer;
  95767. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95768. use PhpCsFixer\Tokenizer\CT;
  95769. use PhpCsFixer\Tokenizer\Token;
  95770. use PhpCsFixer\Tokenizer\Tokens;
  95771. final class DisjunctiveNormalFormTypeParenthesisTransformer extends AbstractTransformer
  95772. {
  95773. public function getPriority(): int
  95774. {
  95775. return -16;
  95776. }
  95777. public function getRequiredPhpVersionId(): int
  95778. {
  95779. return 8_02_00;
  95780. }
  95781. public function process(Tokens $tokens, Token $token, int $index): void
  95782. {
  95783. if ($token->equals('(') && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(CT::T_TYPE_ALTERNATION)) {
  95784. $openIndex = $index;
  95785. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  95786. } elseif ($token->equals(')') && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(CT::T_TYPE_ALTERNATION)) {
  95787. $openIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  95788. $closeIndex = $index;
  95789. } else {
  95790. return;
  95791. }
  95792. $tokens[$openIndex] = new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, '(']);
  95793. $tokens[$closeIndex] = new Token([CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE, ')']);
  95794. }
  95795. public function getCustomTokens(): array
  95796. {
  95797. return [
  95798. CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN,
  95799. CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE,
  95800. ];
  95801. }
  95802. }
  95803. <?php
  95804. declare(strict_types=1);
  95805. namespace PhpCsFixer\Tokenizer\Transformer;
  95806. use PhpCsFixer\Tokenizer\AbstractTypeTransformer;
  95807. use PhpCsFixer\Tokenizer\CT;
  95808. use PhpCsFixer\Tokenizer\Token;
  95809. use PhpCsFixer\Tokenizer\Tokens;
  95810. final class TypeIntersectionTransformer extends AbstractTypeTransformer
  95811. {
  95812. public function getPriority(): int
  95813. {
  95814. return -15;
  95815. }
  95816. public function getRequiredPhpVersionId(): int
  95817. {
  95818. return 8_01_00;
  95819. }
  95820. public function process(Tokens $tokens, Token $token, int $index): void
  95821. {
  95822. $this->doProcess($tokens, $index, [T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, '&']);
  95823. }
  95824. public function getCustomTokens(): array
  95825. {
  95826. return [CT::T_TYPE_INTERSECTION];
  95827. }
  95828. protected function replaceToken(Tokens $tokens, int $index): void
  95829. {
  95830. $tokens[$index] = new Token([CT::T_TYPE_INTERSECTION, '&']);
  95831. }
  95832. }
  95833. <?php
  95834. declare(strict_types=1);
  95835. namespace PhpCsFixer\Tokenizer\Transformer;
  95836. use PhpCsFixer\Tokenizer\AbstractTypeTransformer;
  95837. use PhpCsFixer\Tokenizer\CT;
  95838. use PhpCsFixer\Tokenizer\Token;
  95839. use PhpCsFixer\Tokenizer\Tokens;
  95840. final class TypeAlternationTransformer extends AbstractTypeTransformer
  95841. {
  95842. public function getPriority(): int
  95843. {
  95844. return -15;
  95845. }
  95846. public function getRequiredPhpVersionId(): int
  95847. {
  95848. return 7_01_00;
  95849. }
  95850. public function process(Tokens $tokens, Token $token, int $index): void
  95851. {
  95852. $this->doProcess($tokens, $index, '|');
  95853. }
  95854. public function getCustomTokens(): array
  95855. {
  95856. return [CT::T_TYPE_ALTERNATION];
  95857. }
  95858. protected function replaceToken(Tokens $tokens, int $index): void
  95859. {
  95860. $tokens[$index] = new Token([CT::T_TYPE_ALTERNATION, '|']);
  95861. }
  95862. }
  95863. <?php
  95864. declare(strict_types=1);
  95865. namespace PhpCsFixer\Tokenizer\Transformer;
  95866. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95867. use PhpCsFixer\Tokenizer\CT;
  95868. use PhpCsFixer\Tokenizer\Token;
  95869. use PhpCsFixer\Tokenizer\Tokens;
  95870. final class AttributeTransformer extends AbstractTransformer
  95871. {
  95872. public function getPriority(): int
  95873. {
  95874. return 200;
  95875. }
  95876. public function getRequiredPhpVersionId(): int
  95877. {
  95878. return 8_00_00;
  95879. }
  95880. public function process(Tokens $tokens, Token $token, int $index): void
  95881. {
  95882. if (!$tokens[$index]->isGivenKind(T_ATTRIBUTE)) {
  95883. return;
  95884. }
  95885. $level = 1;
  95886. do {
  95887. ++$index;
  95888. if ($tokens[$index]->equals('[')) {
  95889. ++$level;
  95890. } elseif ($tokens[$index]->equals(']')) {
  95891. --$level;
  95892. }
  95893. } while (0 < $level);
  95894. $tokens[$index] = new Token([CT::T_ATTRIBUTE_CLOSE, ']']);
  95895. }
  95896. public function getCustomTokens(): array
  95897. {
  95898. return [
  95899. CT::T_ATTRIBUTE_CLOSE,
  95900. ];
  95901. }
  95902. }
  95903. <?php
  95904. declare(strict_types=1);
  95905. namespace PhpCsFixer\Tokenizer\Transformer;
  95906. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95907. use PhpCsFixer\Tokenizer\CT;
  95908. use PhpCsFixer\Tokenizer\Token;
  95909. use PhpCsFixer\Tokenizer\Tokens;
  95910. final class BraceClassInstantiationTransformer extends AbstractTransformer
  95911. {
  95912. public function getPriority(): int
  95913. {
  95914. return -2;
  95915. }
  95916. public function getRequiredPhpVersionId(): int
  95917. {
  95918. return 5_00_00;
  95919. }
  95920. public function process(Tokens $tokens, Token $token, int $index): void
  95921. {
  95922. if (!$tokens[$index]->equals('(') || !$tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_NEW)) {
  95923. return;
  95924. }
  95925. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny([
  95926. ')',
  95927. ']',
  95928. [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
  95929. [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
  95930. [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
  95931. [T_ARRAY],
  95932. [T_CLASS],
  95933. [T_ELSEIF],
  95934. [T_FOR],
  95935. [T_FOREACH],
  95936. [T_IF],
  95937. [T_STATIC],
  95938. [T_STRING],
  95939. [T_SWITCH],
  95940. [T_VARIABLE],
  95941. [T_WHILE],
  95942. ])) {
  95943. return;
  95944. }
  95945. $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  95946. $tokens[$index] = new Token([CT::T_BRACE_CLASS_INSTANTIATION_OPEN, '(']);
  95947. $tokens[$closeIndex] = new Token([CT::T_BRACE_CLASS_INSTANTIATION_CLOSE, ')']);
  95948. }
  95949. public function getCustomTokens(): array
  95950. {
  95951. return [CT::T_BRACE_CLASS_INSTANTIATION_OPEN, CT::T_BRACE_CLASS_INSTANTIATION_CLOSE];
  95952. }
  95953. }
  95954. <?php
  95955. declare(strict_types=1);
  95956. namespace PhpCsFixer\Tokenizer\Transformer;
  95957. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95958. use PhpCsFixer\Tokenizer\CT;
  95959. use PhpCsFixer\Tokenizer\Token;
  95960. use PhpCsFixer\Tokenizer\Tokens;
  95961. final class ClassConstantTransformer extends AbstractTransformer
  95962. {
  95963. public function getRequiredPhpVersionId(): int
  95964. {
  95965. return 5_05_00;
  95966. }
  95967. public function process(Tokens $tokens, Token $token, int $index): void
  95968. {
  95969. if (!$token->equalsAny([
  95970. [T_CLASS, 'class'],
  95971. [T_STRING, 'class'],
  95972. ], false)) {
  95973. return;
  95974. }
  95975. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  95976. $prevToken = $tokens[$prevIndex];
  95977. if ($prevToken->isGivenKind(T_DOUBLE_COLON)) {
  95978. $tokens[$index] = new Token([CT::T_CLASS_CONSTANT, $token->getContent()]);
  95979. }
  95980. }
  95981. public function getCustomTokens(): array
  95982. {
  95983. return [CT::T_CLASS_CONSTANT];
  95984. }
  95985. }
  95986. <?php
  95987. declare(strict_types=1);
  95988. namespace PhpCsFixer\Tokenizer\Transformer;
  95989. use PhpCsFixer\Tokenizer\AbstractTransformer;
  95990. use PhpCsFixer\Tokenizer\CT;
  95991. use PhpCsFixer\Tokenizer\FCT;
  95992. use PhpCsFixer\Tokenizer\Token;
  95993. use PhpCsFixer\Tokenizer\Tokens;
  95994. final class UseTransformer extends AbstractTransformer
  95995. {
  95996. private const CLASS_TYPES = [T_TRAIT, FCT::T_ENUM];
  95997. public function getPriority(): int
  95998. {
  95999. return -5;
  96000. }
  96001. public function getRequiredPhpVersionId(): int
  96002. {
  96003. return 5_03_00;
  96004. }
  96005. public function process(Tokens $tokens, Token $token, int $index): void
  96006. {
  96007. if ($token->isGivenKind(T_USE) && $this->isUseForLambda($tokens, $index)) {
  96008. $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);
  96009. return;
  96010. }
  96011. if ($token->isGivenKind(T_CLASS)) {
  96012. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_DOUBLE_COLON)) {
  96013. return;
  96014. }
  96015. } elseif (!$token->isGivenKind(self::CLASS_TYPES)) {
  96016. return;
  96017. }
  96018. $index = $tokens->getNextTokenOfKind($index, ['{']);
  96019. $innerLimit = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
  96020. while ($index < $innerLimit) {
  96021. $token = $tokens[++$index];
  96022. if (!$token->isGivenKind(T_USE)) {
  96023. continue;
  96024. }
  96025. if ($this->isUseForLambda($tokens, $index)) {
  96026. $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);
  96027. } else {
  96028. $tokens[$index] = new Token([CT::T_USE_TRAIT, $token->getContent()]);
  96029. }
  96030. }
  96031. }
  96032. public function getCustomTokens(): array
  96033. {
  96034. return [CT::T_USE_TRAIT, CT::T_USE_LAMBDA];
  96035. }
  96036. private function isUseForLambda(Tokens $tokens, int $index): bool
  96037. {
  96038. $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
  96039. return $nextToken->equals('(');
  96040. }
  96041. }
  96042. <?php
  96043. declare(strict_types=1);
  96044. namespace PhpCsFixer\Tokenizer\Transformer;
  96045. use PhpCsFixer\Tokenizer\AbstractTransformer;
  96046. use PhpCsFixer\Tokenizer\CT;
  96047. use PhpCsFixer\Tokenizer\Token;
  96048. use PhpCsFixer\Tokenizer\Tokens;
  96049. final class NamedArgumentTransformer extends AbstractTransformer
  96050. {
  96051. public function getPriority(): int
  96052. {
  96053. return -15;
  96054. }
  96055. public function getRequiredPhpVersionId(): int
  96056. {
  96057. return 8_00_00;
  96058. }
  96059. public function process(Tokens $tokens, Token $token, int $index): void
  96060. {
  96061. if (!$tokens[$index]->equals(':')) {
  96062. return;
  96063. }
  96064. $stringIndex = $tokens->getPrevMeaningfulToken($index);
  96065. if (!$tokens[$stringIndex]->isGivenKind(T_STRING)) {
  96066. return;
  96067. }
  96068. $preStringIndex = $tokens->getPrevMeaningfulToken($stringIndex);
  96069. if (!$tokens[$preStringIndex]->equalsAny([',', '('])) {
  96070. return;
  96071. }
  96072. $tokens[$stringIndex] = new Token([CT::T_NAMED_ARGUMENT_NAME, $tokens[$stringIndex]->getContent()]);
  96073. $tokens[$index] = new Token([CT::T_NAMED_ARGUMENT_COLON, ':']);
  96074. }
  96075. public function getCustomTokens(): array
  96076. {
  96077. return [
  96078. CT::T_NAMED_ARGUMENT_COLON,
  96079. CT::T_NAMED_ARGUMENT_NAME,
  96080. ];
  96081. }
  96082. }
  96083. <?php
  96084. declare(strict_types=1);
  96085. namespace PhpCsFixer\Tokenizer\Transformer;
  96086. use PhpCsFixer\Tokenizer\AbstractTransformer;
  96087. use PhpCsFixer\Tokenizer\CT;
  96088. use PhpCsFixer\Tokenizer\Token;
  96089. use PhpCsFixer\Tokenizer\Tokens;
  96090. final class ConstructorPromotionTransformer extends AbstractTransformer
  96091. {
  96092. public function getRequiredPhpVersionId(): int
  96093. {
  96094. return 8_00_00;
  96095. }
  96096. public function process(Tokens $tokens, Token $token, int $index): void
  96097. {
  96098. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  96099. return;
  96100. }
  96101. $functionNameIndex = $tokens->getNextMeaningfulToken($index);
  96102. if (!$tokens[$functionNameIndex]->isGivenKind(T_STRING) || '__construct' !== strtolower($tokens[$functionNameIndex]->getContent())) {
  96103. return;
  96104. }
  96105. $openParenthesisIndex = $tokens->getNextMeaningfulToken($functionNameIndex);
  96106. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  96107. for ($argsIndex = $openParenthesisIndex; $argsIndex < $closeParenthesisIndex; ++$argsIndex) {
  96108. if ($tokens[$argsIndex]->isGivenKind(T_PUBLIC)) {
  96109. $tokens[$argsIndex] = new Token([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, $tokens[$argsIndex]->getContent()]);
  96110. } elseif ($tokens[$argsIndex]->isGivenKind(T_PROTECTED)) {
  96111. $tokens[$argsIndex] = new Token([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, $tokens[$argsIndex]->getContent()]);
  96112. } elseif ($tokens[$argsIndex]->isGivenKind(T_PRIVATE)) {
  96113. $tokens[$argsIndex] = new Token([CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, $tokens[$argsIndex]->getContent()]);
  96114. }
  96115. }
  96116. }
  96117. public function getCustomTokens(): array
  96118. {
  96119. return [
  96120. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  96121. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  96122. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  96123. ];
  96124. }
  96125. }
  96126. <?php
  96127. declare(strict_types=1);
  96128. namespace PhpCsFixer\Tokenizer\Processor;
  96129. use PhpCsFixer\Tokenizer\CT;
  96130. use PhpCsFixer\Tokenizer\Token;
  96131. use PhpCsFixer\Tokenizer\Tokens;
  96132. use PhpCsFixer\WhitespacesFixerConfig;
  96133. /**
  96134. @readonly
  96135. */
  96136. final class ImportProcessor
  96137. {
  96138. private WhitespacesFixerConfig $whitespacesConfig;
  96139. public function __construct(WhitespacesFixerConfig $whitespacesConfig)
  96140. {
  96141. $this->whitespacesConfig = $whitespacesConfig;
  96142. }
  96143. public function insertImports(Tokens $tokens, array $imports, int $atIndex): void
  96144. {
  96145. $lineEnding = $this->whitespacesConfig->getLineEnding();
  96146. if (!$tokens[$atIndex]->isWhitespace() || !str_contains($tokens[$atIndex]->getContent(), "\n")) {
  96147. $tokens->insertAt($atIndex, new Token([T_WHITESPACE, $lineEnding]));
  96148. }
  96149. foreach ($imports as $type => $typeImports) {
  96150. sort($typeImports);
  96151. $items = [];
  96152. foreach ($typeImports as $name) {
  96153. $items = array_merge($items, [
  96154. new Token([T_WHITESPACE, $lineEnding]),
  96155. new Token([T_USE, 'use']),
  96156. new Token([T_WHITESPACE, ' ']),
  96157. ]);
  96158. if ('const' === $type) {
  96159. $items[] = new Token([CT::T_CONST_IMPORT, 'const']);
  96160. $items[] = new Token([T_WHITESPACE, ' ']);
  96161. } elseif ('function' === $type) {
  96162. $items[] = new Token([CT::T_FUNCTION_IMPORT, 'function']);
  96163. $items[] = new Token([T_WHITESPACE, ' ']);
  96164. }
  96165. $items = array_merge($items, self::tokenizeName($name));
  96166. $items[] = new Token(';');
  96167. }
  96168. $tokens->insertAt($atIndex, $items);
  96169. }
  96170. }
  96171. public static function tokenizeName(string $name): array
  96172. {
  96173. $parts = explode('\\', $name);
  96174. $newTokens = [];
  96175. if ('' === $parts[0]) {
  96176. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  96177. array_shift($parts);
  96178. }
  96179. foreach ($parts as $part) {
  96180. $newTokens[] = new Token([T_STRING, $part]);
  96181. $newTokens[] = new Token([T_NS_SEPARATOR, '\\']);
  96182. }
  96183. array_pop($newTokens);
  96184. return $newTokens;
  96185. }
  96186. }
  96187. <?php
  96188. declare(strict_types=1);
  96189. namespace PhpCsFixer\Tokenizer;
  96190. abstract class AbstractTypeTransformer extends AbstractTransformer
  96191. {
  96192. private const TYPE_END_TOKENS = [')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT]];
  96193. private const TYPE_TOKENS = [
  96194. '|', '&', '(',
  96195. ...self::TYPE_END_TOKENS,
  96196. [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_INTERSECTION],
  96197. [T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT],
  96198. ];
  96199. abstract protected function replaceToken(Tokens $tokens, int $index): void;
  96200. protected function doProcess(Tokens $tokens, int $index, $originalToken): void
  96201. {
  96202. if (!$tokens[$index]->equals($originalToken)) {
  96203. return;
  96204. }
  96205. if (!$this->isPartOfType($tokens, $index)) {
  96206. return;
  96207. }
  96208. $this->replaceToken($tokens, $index);
  96209. }
  96210. private function isPartOfType(Tokens $tokens, int $index): bool
  96211. {
  96212. $typeColonIndex = $tokens->getTokenNotOfKindSibling($index, -1, self::TYPE_TOKENS);
  96213. if ($tokens[$typeColonIndex]->isGivenKind([T_CATCH, CT::T_TYPE_COLON, T_CONST])) {
  96214. return true;
  96215. }
  96216. $afterTypeIndex = $tokens->getTokenNotOfKindSibling($index, 1, self::TYPE_TOKENS);
  96217. if ($tokens[$afterTypeIndex]->isGivenKind(T_ELLIPSIS)) {
  96218. return true;
  96219. }
  96220. if (!$tokens[$afterTypeIndex]->isGivenKind(T_VARIABLE)) {
  96221. return false;
  96222. }
  96223. $beforeVariableIndex = $tokens->getPrevMeaningfulToken($afterTypeIndex);
  96224. if ($tokens[$beforeVariableIndex]->equals('&')) {
  96225. $prevIndex = $tokens->getPrevTokenOfKind(
  96226. $index,
  96227. [
  96228. '{',
  96229. '}',
  96230. ';',
  96231. [T_CLOSE_TAG],
  96232. [T_FN],
  96233. [T_FUNCTION],
  96234. ],
  96235. );
  96236. return null !== $prevIndex && $tokens[$prevIndex]->isGivenKind([T_FN, T_FUNCTION]);
  96237. }
  96238. return $tokens[$beforeVariableIndex]->equalsAny(self::TYPE_END_TOKENS);
  96239. }
  96240. }
  96241. <?php
  96242. declare(strict_types=1);
  96243. namespace PhpCsFixer\Tokenizer;
  96244. use Symfony\Component\Finder\Finder;
  96245. use Symfony\Component\Finder\SplFileInfo;
  96246. final class Transformers
  96247. {
  96248. private array $items = [];
  96249. private function __construct()
  96250. {
  96251. $this->registerBuiltInTransformers();
  96252. usort($this->items, static fn (TransformerInterface $a, TransformerInterface $b): int => $b->getPriority() <=> $a->getPriority());
  96253. }
  96254. public static function createSingleton(): self
  96255. {
  96256. static $instance = null;
  96257. if (!$instance) {
  96258. $instance = new self();
  96259. }
  96260. return $instance;
  96261. }
  96262. public function transform(Tokens $tokens): void
  96263. {
  96264. foreach ($this->items as $transformer) {
  96265. foreach ($tokens as $index => $token) {
  96266. $transformer->process($tokens, $token, $index);
  96267. }
  96268. }
  96269. }
  96270. private function registerTransformer(TransformerInterface $transformer): void
  96271. {
  96272. if (\PHP_VERSION_ID >= $transformer->getRequiredPhpVersionId()) {
  96273. $this->items[] = $transformer;
  96274. }
  96275. }
  96276. private function registerBuiltInTransformers(): void
  96277. {
  96278. static $registered = false;
  96279. if ($registered) {
  96280. return;
  96281. }
  96282. $registered = true;
  96283. foreach ($this->findBuiltInTransformers() as $transformer) {
  96284. $this->registerTransformer($transformer);
  96285. }
  96286. }
  96287. private function findBuiltInTransformers(): iterable
  96288. {
  96289. foreach (Finder::create()->files()->in(__DIR__.'/Transformer') as $file) {
  96290. $relativeNamespace = $file->getRelativePath();
  96291. $class = __NAMESPACE__.'\Transformer\\'.('' !== $relativeNamespace ? $relativeNamespace.'\\' : '').$file->getBasename('.php');
  96292. $instance = new $class();
  96293. \assert($instance instanceof TransformerInterface);
  96294. yield $instance;
  96295. }
  96296. }
  96297. }
  96298. <?php
  96299. declare(strict_types=1);
  96300. namespace PhpCsFixer\Tokenizer;
  96301. interface TransformerInterface
  96302. {
  96303. public function getCustomTokens(): array;
  96304. public function getName(): string;
  96305. public function getPriority(): int;
  96306. public function getRequiredPhpVersionId(): int;
  96307. public function process(Tokens $tokens, Token $token, int $index): void;
  96308. }
  96309. <?php
  96310. declare(strict_types=1);
  96311. namespace PhpCsFixer\Tokenizer;
  96312. use PhpCsFixer\Utils;
  96313. abstract class AbstractTransformer implements TransformerInterface
  96314. {
  96315. public function getName(): string
  96316. {
  96317. $nameParts = explode('\\', static::class);
  96318. $name = substr(end($nameParts), 0, -\strlen('Transformer'));
  96319. return Utils::camelCaseToUnderscore($name);
  96320. }
  96321. public function getPriority(): int
  96322. {
  96323. return 0;
  96324. }
  96325. abstract public function getCustomTokens(): array;
  96326. }
  96327. <?php
  96328. declare(strict_types=1);
  96329. namespace PhpCsFixer\Tokenizer\Analyzer;
  96330. use PhpCsFixer\DocBlock\TypeExpression;
  96331. use PhpCsFixer\Preg;
  96332. use PhpCsFixer\Tokenizer\Analyzer\Analysis\DataProviderAnalysis;
  96333. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  96334. use PhpCsFixer\Tokenizer\FCT;
  96335. use PhpCsFixer\Tokenizer\Tokens;
  96336. /**
  96337. @phpstan-import-type
  96338. */
  96339. final class DataProviderAnalyzer
  96340. {
  96341. private const REGEX_CLASS = '(?:\\\?+'.TypeExpression::REGEX_IDENTIFIER
  96342. .'(\\\\'.TypeExpression::REGEX_IDENTIFIER.')*+)';
  96343. public function getDataProviders(Tokens $tokens, int $startIndex, int $endIndex): array
  96344. {
  96345. $fullyQualifiedNameAnalyzer = new FullyQualifiedNameAnalyzer($tokens);
  96346. $methods = $this->getMethods($tokens, $startIndex, $endIndex);
  96347. $dataProviders = [];
  96348. foreach ($methods as $methodIndex) {
  96349. [$attributeIndex, $docCommentIndex] = $this->getAttributeIndexAndDocCommentIndices($tokens, $methodIndex);
  96350. if (null !== $attributeIndex) {
  96351. foreach (AttributeAnalyzer::collect($tokens, $attributeIndex) as $attributeAnalysis) {
  96352. foreach ($attributeAnalysis->getAttributes() as $attribute) {
  96353. $dataProviderNameIndex = $this->getDataProviderNameIndex($tokens, $fullyQualifiedNameAnalyzer, $attribute);
  96354. if (null === $dataProviderNameIndex) {
  96355. continue;
  96356. }
  96357. $dataProviders[substr($tokens[$dataProviderNameIndex]->getContent(), 1, -1)][] = [$dataProviderNameIndex, 0];
  96358. }
  96359. }
  96360. }
  96361. if (null !== $docCommentIndex) {
  96362. Preg::matchAll(
  96363. '/@dataProvider\h+(('.self::REGEX_CLASS.'::)?'.TypeExpression::REGEX_IDENTIFIER.')/',
  96364. $tokens[$docCommentIndex]->getContent(),
  96365. $matches,
  96366. PREG_OFFSET_CAPTURE
  96367. );
  96368. foreach ($matches[1] as $k => [$matchName]) {
  96369. \assert(isset($matches[0][$k]));
  96370. $dataProviders[$matchName][] = [$docCommentIndex, $matches[0][$k][1]];
  96371. }
  96372. }
  96373. }
  96374. $dataProviderAnalyses = [];
  96375. foreach ($dataProviders as $dataProviderName => $dataProviderUsages) {
  96376. $lowercaseDataProviderName = strtolower($dataProviderName);
  96377. if (!\array_key_exists($lowercaseDataProviderName, $methods)) {
  96378. continue;
  96379. }
  96380. $dataProviderAnalyses[$methods[$lowercaseDataProviderName]] = new DataProviderAnalysis(
  96381. $tokens[$methods[$lowercaseDataProviderName]]->getContent(),
  96382. $methods[$lowercaseDataProviderName],
  96383. $dataProviderUsages,
  96384. );
  96385. }
  96386. ksort($dataProviderAnalyses);
  96387. return array_values($dataProviderAnalyses);
  96388. }
  96389. private function getMethods(Tokens $tokens, int $startIndex, int $endIndex): array
  96390. {
  96391. $functions = [];
  96392. for ($index = $startIndex; $index < $endIndex; ++$index) {
  96393. if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
  96394. continue;
  96395. }
  96396. $functionNameIndex = $tokens->getNextNonWhitespace($index);
  96397. if (!$tokens[$functionNameIndex]->isGivenKind(T_STRING)) {
  96398. continue;
  96399. }
  96400. $functions[strtolower($tokens[$functionNameIndex]->getContent())] = $functionNameIndex;
  96401. }
  96402. return $functions;
  96403. }
  96404. private function getAttributeIndexAndDocCommentIndices(Tokens $tokens, int $index): array
  96405. {
  96406. $attributeIndex = null;
  96407. $docCommentIndex = null;
  96408. while (!$tokens[$index]->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
  96409. --$index;
  96410. if ($tokens[$index]->isGivenKind(FCT::T_ATTRIBUTE)) {
  96411. $attributeIndex = $index;
  96412. } elseif ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  96413. $docCommentIndex = $index;
  96414. }
  96415. }
  96416. return [$attributeIndex, $docCommentIndex];
  96417. }
  96418. private function getDataProviderNameIndex(Tokens $tokens, FullyQualifiedNameAnalyzer $fullyQualifiedNameAnalyzer, array $attribute): ?int
  96419. {
  96420. $fullyQualifiedName = $fullyQualifiedNameAnalyzer->getFullyQualifiedName(
  96421. $attribute['name'],
  96422. $tokens->getNextMeaningfulToken($attribute['start']),
  96423. NamespaceUseAnalysis::TYPE_CLASS,
  96424. );
  96425. if ('PHPUnit\Framework\Attributes\DataProvider' !== $fullyQualifiedName) {
  96426. return null;
  96427. }
  96428. $closeParenthesisIndex = $tokens->getPrevTokenOfKind($attribute['end'] + 1, [')', [T_ATTRIBUTE]]);
  96429. if ($tokens[$closeParenthesisIndex]->isGivenKind(T_ATTRIBUTE)) {
  96430. return null;
  96431. }
  96432. $dataProviderNameIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex);
  96433. if (!$tokens[$dataProviderNameIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
  96434. return null;
  96435. }
  96436. $openParenthesisIndex = $tokens->getPrevMeaningfulToken($dataProviderNameIndex);
  96437. if (!$tokens[$openParenthesisIndex]->equals('(')) {
  96438. return null;
  96439. }
  96440. return $dataProviderNameIndex;
  96441. }
  96442. }
  96443. <?php
  96444. declare(strict_types=1);
  96445. namespace PhpCsFixer\Tokenizer\Analyzer;
  96446. use PhpCsFixer\Tokenizer\CT;
  96447. use PhpCsFixer\Tokenizer\Tokens;
  96448. final class ReferenceAnalyzer
  96449. {
  96450. public function isReference(Tokens $tokens, int $index): bool
  96451. {
  96452. if ($tokens[$index]->isGivenKind(CT::T_RETURN_REF)) {
  96453. return true;
  96454. }
  96455. if (!$tokens[$index]->equals('&')) {
  96456. return false;
  96457. }
  96458. $index = $tokens->getPrevMeaningfulToken($index);
  96459. if ($tokens[$index]->equalsAny(['=', [T_AS], [T_CALLABLE], [T_DOUBLE_ARROW], [CT::T_ARRAY_TYPEHINT]])) {
  96460. return true;
  96461. }
  96462. if ($tokens[$index]->isGivenKind(T_STRING)) {
  96463. $index = $tokens->getPrevMeaningfulToken($index);
  96464. }
  96465. return $tokens[$index]->equalsAny(['(', ',', [T_NS_SEPARATOR], [CT::T_NULLABLE_TYPE]]);
  96466. }
  96467. }
  96468. <?php
  96469. declare(strict_types=1);
  96470. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96471. /**
  96472. @readonly
  96473. */
  96474. final class MatchAnalysis extends AbstractControlCaseStructuresAnalysis
  96475. {
  96476. private ?DefaultAnalysis $defaultAnalysis;
  96477. public function __construct(int $index, int $open, int $close, ?DefaultAnalysis $defaultAnalysis)
  96478. {
  96479. parent::__construct($index, $open, $close);
  96480. $this->defaultAnalysis = $defaultAnalysis;
  96481. }
  96482. public function getDefaultAnalysis(): ?DefaultAnalysis
  96483. {
  96484. return $this->defaultAnalysis;
  96485. }
  96486. }
  96487. <?php
  96488. declare(strict_types=1);
  96489. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96490. /**
  96491. @readonly
  96492. */
  96493. final class SwitchAnalysis extends AbstractControlCaseStructuresAnalysis
  96494. {
  96495. private array $cases;
  96496. private ?DefaultAnalysis $defaultAnalysis;
  96497. public function __construct(int $index, int $open, int $close, array $cases, ?DefaultAnalysis $defaultAnalysis)
  96498. {
  96499. parent::__construct($index, $open, $close);
  96500. $this->cases = $cases;
  96501. $this->defaultAnalysis = $defaultAnalysis;
  96502. }
  96503. public function getCases(): array
  96504. {
  96505. return $this->cases;
  96506. }
  96507. public function getDefaultAnalysis(): ?DefaultAnalysis
  96508. {
  96509. return $this->defaultAnalysis;
  96510. }
  96511. }
  96512. <?php
  96513. declare(strict_types=1);
  96514. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96515. /**
  96516. @readonly
  96517. @phpstan-type
  96518. @phpstan-type
  96519. */
  96520. final class AttributeAnalysis
  96521. {
  96522. private int $startIndex;
  96523. private int $endIndex;
  96524. private int $openingBracketIndex;
  96525. private int $closingBracketIndex;
  96526. private array $attributes;
  96527. public function __construct(int $startIndex, int $endIndex, int $openingBracketIndex, int $closingBracketIndex, array $attributes)
  96528. {
  96529. $this->startIndex = $startIndex;
  96530. $this->endIndex = $endIndex;
  96531. $this->openingBracketIndex = $openingBracketIndex;
  96532. $this->closingBracketIndex = $closingBracketIndex;
  96533. $this->attributes = $attributes;
  96534. }
  96535. public function getStartIndex(): int
  96536. {
  96537. return $this->startIndex;
  96538. }
  96539. public function getEndIndex(): int
  96540. {
  96541. return $this->endIndex;
  96542. }
  96543. public function getOpeningBracketIndex(): int
  96544. {
  96545. return $this->openingBracketIndex;
  96546. }
  96547. public function getClosingBracketIndex(): int
  96548. {
  96549. return $this->closingBracketIndex;
  96550. }
  96551. public function getAttributes(): array
  96552. {
  96553. return $this->attributes;
  96554. }
  96555. }
  96556. <?php
  96557. declare(strict_types=1);
  96558. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96559. /**
  96560. @readonly
  96561. @phpstan-type
  96562. */
  96563. final class NamespaceUseAnalysis implements StartEndTokenAwareAnalysis
  96564. {
  96565. public const TYPE_CLASS = 1;
  96566. public const TYPE_FUNCTION = 2;
  96567. public const TYPE_CONSTANT = 3;
  96568. private string $fullName;
  96569. private string $shortName;
  96570. private bool $isInMulti;
  96571. private bool $isAliased;
  96572. private int $startIndex;
  96573. private int $endIndex;
  96574. private ?int $chunkStartIndex;
  96575. private ?int $chunkEndIndex;
  96576. private int $type;
  96577. public function __construct(
  96578. int $type,
  96579. string $fullName,
  96580. string $shortName,
  96581. bool $isAliased,
  96582. bool $isInMulti,
  96583. int $startIndex,
  96584. int $endIndex,
  96585. ?int $chunkStartIndex = null,
  96586. ?int $chunkEndIndex = null
  96587. ) {
  96588. if (true === $isInMulti && (null === $chunkStartIndex || null === $chunkEndIndex)) {
  96589. throw new \LogicException('Chunk start and end index must be set when the import is part of a multi-use statement.');
  96590. }
  96591. $this->type = $type;
  96592. $this->fullName = $fullName;
  96593. $this->shortName = $shortName;
  96594. $this->isAliased = $isAliased;
  96595. $this->isInMulti = $isInMulti;
  96596. $this->startIndex = $startIndex;
  96597. $this->endIndex = $endIndex;
  96598. $this->chunkStartIndex = $chunkStartIndex;
  96599. $this->chunkEndIndex = $chunkEndIndex;
  96600. }
  96601. public function getFullName(): string
  96602. {
  96603. return $this->fullName;
  96604. }
  96605. public function getShortName(): string
  96606. {
  96607. return $this->shortName;
  96608. }
  96609. public function isAliased(): bool
  96610. {
  96611. return $this->isAliased;
  96612. }
  96613. public function isInMulti(): bool
  96614. {
  96615. return $this->isInMulti;
  96616. }
  96617. public function getStartIndex(): int
  96618. {
  96619. return $this->startIndex;
  96620. }
  96621. public function getEndIndex(): int
  96622. {
  96623. return $this->endIndex;
  96624. }
  96625. public function getChunkStartIndex(): ?int
  96626. {
  96627. return $this->chunkStartIndex;
  96628. }
  96629. public function getChunkEndIndex(): ?int
  96630. {
  96631. return $this->chunkEndIndex;
  96632. }
  96633. public function getType(): int
  96634. {
  96635. return $this->type;
  96636. }
  96637. public function getHumanFriendlyType(): string
  96638. {
  96639. return [
  96640. self::TYPE_CLASS => 'class',
  96641. self::TYPE_FUNCTION => 'function',
  96642. self::TYPE_CONSTANT => 'constant',
  96643. ][$this->type];
  96644. }
  96645. public function isClass(): bool
  96646. {
  96647. return self::TYPE_CLASS === $this->type;
  96648. }
  96649. public function isFunction(): bool
  96650. {
  96651. return self::TYPE_FUNCTION === $this->type;
  96652. }
  96653. public function isConstant(): bool
  96654. {
  96655. return self::TYPE_CONSTANT === $this->type;
  96656. }
  96657. }
  96658. <?php
  96659. declare(strict_types=1);
  96660. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96661. /**
  96662. @readonly
  96663. */
  96664. abstract class AbstractControlCaseStructuresAnalysis
  96665. {
  96666. private int $index;
  96667. private int $open;
  96668. private int $close;
  96669. public function __construct(int $index, int $open, int $close)
  96670. {
  96671. $this->index = $index;
  96672. $this->open = $open;
  96673. $this->close = $close;
  96674. }
  96675. public function getIndex(): int
  96676. {
  96677. return $this->index;
  96678. }
  96679. public function getOpenIndex(): int
  96680. {
  96681. return $this->open;
  96682. }
  96683. public function getCloseIndex(): int
  96684. {
  96685. return $this->close;
  96686. }
  96687. }
  96688. <?php
  96689. declare(strict_types=1);
  96690. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96691. use PhpCsFixer\Console\Application;
  96692. use PhpCsFixer\Utils;
  96693. /**
  96694. @readonly
  96695. */
  96696. final class DataProviderAnalysis
  96697. {
  96698. private string $name;
  96699. private int $nameIndex;
  96700. private array $usageIndices;
  96701. public function __construct(string $name, int $nameIndex, array $usageIndices)
  96702. {
  96703. if ([] === $usageIndices || !array_is_list($usageIndices)) {
  96704. Utils::triggerDeprecation(new \InvalidArgumentException(\sprintf(
  96705. 'Parameter "usageIndices" should be a non-empty-list. This will be enforced in version %d.0.',
  96706. Application::getMajorVersion() + 1
  96707. )));
  96708. }
  96709. $this->name = $name;
  96710. $this->nameIndex = $nameIndex;
  96711. $this->usageIndices = $usageIndices;
  96712. }
  96713. public function getName(): string
  96714. {
  96715. return $this->name;
  96716. }
  96717. public function getNameIndex(): int
  96718. {
  96719. return $this->nameIndex;
  96720. }
  96721. public function getUsageIndices(): array
  96722. {
  96723. return $this->usageIndices;
  96724. }
  96725. }
  96726. <?php
  96727. declare(strict_types=1);
  96728. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96729. /**
  96730. @readonly
  96731. */
  96732. interface StartEndTokenAwareAnalysis
  96733. {
  96734. public function getStartIndex(): int;
  96735. public function getEndIndex(): int;
  96736. }
  96737. <?php
  96738. declare(strict_types=1);
  96739. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96740. /**
  96741. @readonly
  96742. */
  96743. final class TypeAnalysis implements StartEndTokenAwareAnalysis
  96744. {
  96745. private const RESERVED_TYPES = [
  96746. 'array',
  96747. 'bool',
  96748. 'callable',
  96749. 'false',
  96750. 'float',
  96751. 'int',
  96752. 'iterable',
  96753. 'list',
  96754. 'mixed',
  96755. 'never',
  96756. 'null',
  96757. 'object',
  96758. 'parent',
  96759. 'resource',
  96760. 'self',
  96761. 'static',
  96762. 'string',
  96763. 'true',
  96764. 'void',
  96765. ];
  96766. private string $name;
  96767. private ?int $startIndex;
  96768. private ?int $endIndex;
  96769. private bool $nullable;
  96770. public function __construct(string $name, ?int $startIndex = null, ?int $endIndex = null)
  96771. {
  96772. if (str_starts_with($name, '?')) {
  96773. $this->name = substr($name, 1);
  96774. $this->nullable = true;
  96775. } elseif (\PHP_VERSION_ID >= 8_00_00) {
  96776. $this->name = $name;
  96777. $this->nullable = \in_array('null', array_map('trim', explode('|', strtolower($name))), true);
  96778. } else {
  96779. $this->name = $name;
  96780. $this->nullable = false;
  96781. }
  96782. $this->startIndex = $startIndex;
  96783. $this->endIndex = $endIndex;
  96784. }
  96785. public function getName(): string
  96786. {
  96787. return $this->name;
  96788. }
  96789. public function getStartIndex(): int
  96790. {
  96791. if (null === $this->startIndex) {
  96792. throw new \RuntimeException('TypeAnalysis: no start index.');
  96793. }
  96794. return $this->startIndex;
  96795. }
  96796. public function getEndIndex(): int
  96797. {
  96798. if (null === $this->endIndex) {
  96799. throw new \RuntimeException('TypeAnalysis: no end index.');
  96800. }
  96801. return $this->endIndex;
  96802. }
  96803. public function isReservedType(): bool
  96804. {
  96805. return \in_array(strtolower($this->name), self::RESERVED_TYPES, true);
  96806. }
  96807. public function isNullable(): bool
  96808. {
  96809. return $this->nullable;
  96810. }
  96811. }
  96812. <?php
  96813. declare(strict_types=1);
  96814. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96815. /**
  96816. @readonly
  96817. */
  96818. final class DefaultAnalysis
  96819. {
  96820. private int $index;
  96821. private int $colonIndex;
  96822. public function __construct(int $index, int $colonIndex)
  96823. {
  96824. $this->index = $index;
  96825. $this->colonIndex = $colonIndex;
  96826. }
  96827. public function getIndex(): int
  96828. {
  96829. return $this->index;
  96830. }
  96831. public function getColonIndex(): int
  96832. {
  96833. return $this->colonIndex;
  96834. }
  96835. }
  96836. <?php
  96837. declare(strict_types=1);
  96838. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96839. /**
  96840. @readonly
  96841. */
  96842. final class NamespaceAnalysis implements StartEndTokenAwareAnalysis
  96843. {
  96844. private string $fullName;
  96845. private string $shortName;
  96846. private int $startIndex;
  96847. private int $endIndex;
  96848. private int $scopeStartIndex;
  96849. private int $scopeEndIndex;
  96850. public function __construct(string $fullName, string $shortName, int $startIndex, int $endIndex, int $scopeStartIndex, int $scopeEndIndex)
  96851. {
  96852. $this->fullName = $fullName;
  96853. $this->shortName = $shortName;
  96854. $this->startIndex = $startIndex;
  96855. $this->endIndex = $endIndex;
  96856. $this->scopeStartIndex = $scopeStartIndex;
  96857. $this->scopeEndIndex = $scopeEndIndex;
  96858. }
  96859. public function getFullName(): string
  96860. {
  96861. return $this->fullName;
  96862. }
  96863. public function getShortName(): string
  96864. {
  96865. return $this->shortName;
  96866. }
  96867. public function getStartIndex(): int
  96868. {
  96869. return $this->startIndex;
  96870. }
  96871. public function getEndIndex(): int
  96872. {
  96873. return $this->endIndex;
  96874. }
  96875. public function getScopeStartIndex(): int
  96876. {
  96877. return $this->scopeStartIndex;
  96878. }
  96879. public function getScopeEndIndex(): int
  96880. {
  96881. return $this->scopeEndIndex;
  96882. }
  96883. public function isGlobalNamespace(): bool
  96884. {
  96885. return '' === $this->getFullName();
  96886. }
  96887. }
  96888. <?php
  96889. declare(strict_types=1);
  96890. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96891. /**
  96892. @readonly
  96893. */
  96894. final class EnumAnalysis extends AbstractControlCaseStructuresAnalysis
  96895. {
  96896. private array $cases;
  96897. public function __construct(int $index, int $open, int $close, array $cases)
  96898. {
  96899. parent::__construct($index, $open, $close);
  96900. $this->cases = $cases;
  96901. }
  96902. public function getCases(): array
  96903. {
  96904. return $this->cases;
  96905. }
  96906. }
  96907. <?php
  96908. declare(strict_types=1);
  96909. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96910. /**
  96911. @readonly
  96912. */
  96913. final class CaseAnalysis
  96914. {
  96915. private int $index;
  96916. private int $colonIndex;
  96917. public function __construct(int $index, int $colonIndex)
  96918. {
  96919. $this->index = $index;
  96920. $this->colonIndex = $colonIndex;
  96921. }
  96922. public function getIndex(): int
  96923. {
  96924. return $this->index;
  96925. }
  96926. public function getColonIndex(): int
  96927. {
  96928. return $this->colonIndex;
  96929. }
  96930. }
  96931. <?php
  96932. declare(strict_types=1);
  96933. namespace PhpCsFixer\Tokenizer\Analyzer\Analysis;
  96934. /**
  96935. @readonly
  96936. */
  96937. final class ArgumentAnalysis
  96938. {
  96939. private ?string $name;
  96940. private ?int $nameIndex;
  96941. private ?string $default;
  96942. private ?TypeAnalysis $typeAnalysis;
  96943. public function __construct(?string $name, ?int $nameIndex, ?string $default, ?TypeAnalysis $typeAnalysis = null)
  96944. {
  96945. $this->name = $name;
  96946. $this->nameIndex = $nameIndex;
  96947. $this->default = $default ?? null;
  96948. $this->typeAnalysis = $typeAnalysis ?? null;
  96949. }
  96950. public function getDefault(): ?string
  96951. {
  96952. return $this->default;
  96953. }
  96954. public function hasDefault(): bool
  96955. {
  96956. return null !== $this->default;
  96957. }
  96958. public function getName(): ?string
  96959. {
  96960. return $this->name;
  96961. }
  96962. public function getNameIndex(): ?int
  96963. {
  96964. return $this->nameIndex;
  96965. }
  96966. public function getTypeAnalysis(): ?TypeAnalysis
  96967. {
  96968. return $this->typeAnalysis;
  96969. }
  96970. public function hasTypeAnalysis(): bool
  96971. {
  96972. return null !== $this->typeAnalysis;
  96973. }
  96974. }
  96975. <?php
  96976. declare(strict_types=1);
  96977. namespace PhpCsFixer\Tokenizer\Analyzer;
  96978. use PhpCsFixer\Tokenizer\Analyzer\Analysis\AbstractControlCaseStructuresAnalysis;
  96979. use PhpCsFixer\Tokenizer\Analyzer\Analysis\CaseAnalysis;
  96980. use PhpCsFixer\Tokenizer\Analyzer\Analysis\DefaultAnalysis;
  96981. use PhpCsFixer\Tokenizer\Analyzer\Analysis\EnumAnalysis;
  96982. use PhpCsFixer\Tokenizer\Analyzer\Analysis\MatchAnalysis;
  96983. use PhpCsFixer\Tokenizer\Analyzer\Analysis\SwitchAnalysis;
  96984. use PhpCsFixer\Tokenizer\FCT;
  96985. use PhpCsFixer\Tokenizer\Tokens;
  96986. final class ControlCaseStructuresAnalyzer
  96987. {
  96988. private const SUPPORTED_TYPES_WITH_CASE_OR_DEFAULT = [
  96989. T_SWITCH,
  96990. FCT::T_MATCH,
  96991. FCT::T_ENUM,
  96992. ];
  96993. public static function findControlStructures(Tokens $tokens, array $types): \Generator
  96994. {
  96995. if (\count($types) < 1) {
  96996. return;
  96997. }
  96998. foreach ($types as $type) {
  96999. if (!\in_array($type, self::SUPPORTED_TYPES_WITH_CASE_OR_DEFAULT, true)) {
  97000. throw new \InvalidArgumentException(\sprintf('Unexpected type "%d".', $type));
  97001. }
  97002. }
  97003. if (!$tokens->isAnyTokenKindsFound($types)) {
  97004. return;
  97005. }
  97006. $depth = -1;
  97007. $stack = [];
  97008. $isTypeOfInterest = false;
  97009. foreach ($tokens as $index => $token) {
  97010. if ($token->isGivenKind(self::SUPPORTED_TYPES_WITH_CASE_OR_DEFAULT)) {
  97011. ++$depth;
  97012. $stack[$depth] = [
  97013. 'kind' => $token->getId(),
  97014. 'index' => $index,
  97015. 'brace_count' => 0,
  97016. 'cases' => [],
  97017. 'default' => null,
  97018. 'alternative_syntax' => false,
  97019. ];
  97020. $isTypeOfInterest = \in_array($stack[$depth]['kind'], $types, true);
  97021. if ($token->isGivenKind(T_SWITCH)) {
  97022. $index = $tokens->getNextMeaningfulToken($index);
  97023. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  97024. $stack[$depth]['open'] = $tokens->getNextMeaningfulToken($index);
  97025. $stack[$depth]['alternative_syntax'] = $tokens[$stack[$depth]['open']]->equals(':');
  97026. } elseif ($token->isGivenKind(FCT::T_MATCH)) {
  97027. $index = $tokens->getNextMeaningfulToken($index);
  97028. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  97029. $stack[$depth]['open'] = $tokens->getNextMeaningfulToken($index);
  97030. } elseif ($token->isGivenKind(FCT::T_ENUM)) {
  97031. $stack[$depth]['open'] = $tokens->getNextTokenOfKind($index, ['{']);
  97032. }
  97033. continue;
  97034. }
  97035. if ($depth < 0) {
  97036. continue;
  97037. }
  97038. if ($token->equals('{')) {
  97039. ++$stack[$depth]['brace_count'];
  97040. continue;
  97041. }
  97042. if ($token->equals('}')) {
  97043. --$stack[$depth]['brace_count'];
  97044. if (0 === $stack[$depth]['brace_count']) {
  97045. if ($stack[$depth]['alternative_syntax']) {
  97046. continue;
  97047. }
  97048. if ($isTypeOfInterest) {
  97049. $stack[$depth]['end'] = $index;
  97050. yield $stack[$depth]['index'] => self::buildControlCaseStructureAnalysis($stack[$depth]);
  97051. }
  97052. array_pop($stack);
  97053. --$depth;
  97054. if ($depth < -1) {
  97055. throw new \RuntimeException('Analysis depth count failure.');
  97056. }
  97057. if (isset($stack[$depth]['kind'])) {
  97058. $isTypeOfInterest = \in_array($stack[$depth]['kind'], $types, true);
  97059. }
  97060. }
  97061. continue;
  97062. }
  97063. if ($tokens[$index]->isGivenKind(T_ENDSWITCH)) {
  97064. if (!$stack[$depth]['alternative_syntax']) {
  97065. throw new \RuntimeException('Analysis syntax failure, unexpected "T_ENDSWITCH".');
  97066. }
  97067. if (T_SWITCH !== $stack[$depth]['kind']) {
  97068. throw new \RuntimeException('Analysis type failure, unexpected "T_ENDSWITCH".');
  97069. }
  97070. if (0 !== $stack[$depth]['brace_count']) {
  97071. throw new \RuntimeException('Analysis count failure, unexpected "T_ENDSWITCH".');
  97072. }
  97073. $index = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  97074. if ($isTypeOfInterest) {
  97075. $stack[$depth]['end'] = $index;
  97076. yield $stack[$depth]['index'] => self::buildControlCaseStructureAnalysis($stack[$depth]);
  97077. }
  97078. array_pop($stack);
  97079. --$depth;
  97080. if ($depth < -1) {
  97081. throw new \RuntimeException('Analysis depth count failure ("T_ENDSWITCH").');
  97082. }
  97083. if (isset($stack[$depth]['kind'])) {
  97084. $isTypeOfInterest = \in_array($stack[$depth]['kind'], $types, true);
  97085. }
  97086. }
  97087. if (!$isTypeOfInterest) {
  97088. continue;
  97089. }
  97090. if ($token->isGivenKind(T_CASE)) {
  97091. $stack[$depth]['cases'][] = ['index' => $index, 'open' => self::findCaseOpen($tokens, $stack[$depth]['kind'], $index)];
  97092. } elseif ($token->isGivenKind(T_DEFAULT)) {
  97093. if (null !== $stack[$depth]['default']) {
  97094. throw new \RuntimeException('Analysis multiple "default" found.');
  97095. }
  97096. $stack[$depth]['default'] = ['index' => $index, 'open' => self::findDefaultOpen($tokens, $stack[$depth]['kind'], $index)];
  97097. }
  97098. }
  97099. }
  97100. private static function buildControlCaseStructureAnalysis(array $analysis): AbstractControlCaseStructuresAnalysis
  97101. {
  97102. $default = null === $analysis['default']
  97103. ? null
  97104. : new DefaultAnalysis($analysis['default']['index'], $analysis['default']['open']);
  97105. $cases = [];
  97106. foreach ($analysis['cases'] as $case) {
  97107. $cases[$case['index']] = new CaseAnalysis($case['index'], $case['open']);
  97108. }
  97109. sort($cases);
  97110. if (T_SWITCH === $analysis['kind']) {
  97111. return new SwitchAnalysis(
  97112. $analysis['index'],
  97113. $analysis['open'],
  97114. $analysis['end'],
  97115. $cases,
  97116. $default
  97117. );
  97118. }
  97119. if (FCT::T_ENUM === $analysis['kind']) {
  97120. return new EnumAnalysis(
  97121. $analysis['index'],
  97122. $analysis['open'],
  97123. $analysis['end'],
  97124. $cases
  97125. );
  97126. }
  97127. if (FCT::T_MATCH === $analysis['kind']) {
  97128. return new MatchAnalysis(
  97129. $analysis['index'],
  97130. $analysis['open'],
  97131. $analysis['end'],
  97132. $default
  97133. );
  97134. }
  97135. throw new \InvalidArgumentException(\sprintf('Unexpected type "%d".', $analysis['kind']));
  97136. }
  97137. private static function findCaseOpen(Tokens $tokens, int $kind, int $index): int
  97138. {
  97139. if (T_SWITCH === $kind) {
  97140. $ternariesCount = 0;
  97141. --$index;
  97142. while (true) {
  97143. ++$index;
  97144. if ($tokens[$index]->equalsAny(['(', '{'])) {
  97145. $type = Tokens::detectBlockType($tokens[$index]);
  97146. $index = $tokens->findBlockEnd($type['type'], $index);
  97147. continue;
  97148. }
  97149. if ($tokens[$index]->equals('?')) {
  97150. ++$ternariesCount;
  97151. continue;
  97152. }
  97153. if ($tokens[$index]->equalsAny([':', ';'])) {
  97154. if (0 === $ternariesCount) {
  97155. break;
  97156. }
  97157. --$ternariesCount;
  97158. }
  97159. }
  97160. return $index;
  97161. }
  97162. if (FCT::T_ENUM === $kind) {
  97163. return $tokens->getNextTokenOfKind($index, ['=', ';']);
  97164. }
  97165. throw new \InvalidArgumentException(\sprintf('Unexpected case for type "%d".', $kind));
  97166. }
  97167. private static function findDefaultOpen(Tokens $tokens, int $kind, int $index): int
  97168. {
  97169. if (T_SWITCH === $kind) {
  97170. return $tokens->getNextTokenOfKind($index, [':', ';']);
  97171. }
  97172. if (FCT::T_MATCH === $kind) {
  97173. return $tokens->getNextTokenOfKind($index, [[T_DOUBLE_ARROW]]);
  97174. }
  97175. throw new \InvalidArgumentException(\sprintf('Unexpected default for type "%d".', $kind));
  97176. }
  97177. }
  97178. <?php
  97179. declare(strict_types=1);
  97180. namespace PhpCsFixer\Tokenizer\Analyzer;
  97181. use PhpCsFixer\Tokenizer\Token;
  97182. use PhpCsFixer\Tokenizer\Tokens;
  97183. final class BlocksAnalyzer
  97184. {
  97185. public function isBlock(Tokens $tokens, int $openIndex, int $closeIndex): bool
  97186. {
  97187. if (!$tokens->offsetExists($openIndex)) {
  97188. throw new \InvalidArgumentException(\sprintf('Tokex index %d for potential block opening does not exist.', $openIndex));
  97189. }
  97190. if (!$tokens->offsetExists($closeIndex)) {
  97191. throw new \InvalidArgumentException(\sprintf('Token index %d for potential block closure does not exist.', $closeIndex));
  97192. }
  97193. $blockType = $this->getBlockType($tokens[$openIndex]);
  97194. if (null === $blockType) {
  97195. return false;
  97196. }
  97197. return $closeIndex === $tokens->findBlockEnd($blockType, $openIndex);
  97198. }
  97199. private function getBlockType(Token $token): ?int
  97200. {
  97201. foreach (Tokens::getBlockEdgeDefinitions() as $blockType => $definition) {
  97202. if ($token->equals($definition['start'])) {
  97203. return $blockType;
  97204. }
  97205. }
  97206. return null;
  97207. }
  97208. }
  97209. <?php
  97210. declare(strict_types=1);
  97211. namespace PhpCsFixer\Tokenizer\Analyzer;
  97212. use PhpCsFixer\Tokenizer\Tokens;
  97213. final class GotoLabelAnalyzer
  97214. {
  97215. public function belongsToGoToLabel(Tokens $tokens, int $index): bool
  97216. {
  97217. if (!$tokens[$index]->equals(':')) {
  97218. return false;
  97219. }
  97220. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($index);
  97221. if (!$tokens[$prevMeaningfulTokenIndex]->isGivenKind(T_STRING)) {
  97222. return false;
  97223. }
  97224. $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($prevMeaningfulTokenIndex);
  97225. return $tokens[$prevMeaningfulTokenIndex]->equalsAny([':', ';', '{', '}', [T_OPEN_TAG]]);
  97226. }
  97227. }
  97228. <?php
  97229. declare(strict_types=1);
  97230. namespace PhpCsFixer\Tokenizer\Analyzer;
  97231. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  97232. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  97233. use PhpCsFixer\Tokenizer\Tokens;
  97234. final class FullyQualifiedNameAnalyzer
  97235. {
  97236. private Tokens $tokens;
  97237. private array $namespaceAnalyses = [];
  97238. private array $namespaceUseAnalyses = [];
  97239. public function __construct(Tokens $tokens)
  97240. {
  97241. $this->tokens = $tokens;
  97242. }
  97243. public function getFullyQualifiedName(string $name, int $indexInNamespace, int $importType): string
  97244. {
  97245. return ltrim($this->getFullyQualifiedNameWithPossiblyLeadingSlash($name, $indexInNamespace, $importType), '\\');
  97246. }
  97247. private function getFullyQualifiedNameWithPossiblyLeadingSlash(string $name, int $indexInNamespace, int $importType): string
  97248. {
  97249. if ('\\' === $name[0]) {
  97250. return $name;
  97251. }
  97252. $namespaceAnalysis = $this->getNamespaceAnalysis($indexInNamespace);
  97253. $this->namespaceUseAnalyses[$namespaceAnalysis->getStartIndex()] ??= (new NamespaceUsesAnalyzer())->getDeclarationsInNamespace($this->tokens, $namespaceAnalysis);
  97254. \assert(isset($this->namespaceUseAnalyses[$namespaceAnalysis->getStartIndex()]));
  97255. $declarations = [];
  97256. foreach ($this->namespaceUseAnalyses[$namespaceAnalysis->getStartIndex()] as $namespaceUseAnalysis) {
  97257. if ($namespaceUseAnalysis->getType() !== $importType) {
  97258. continue;
  97259. }
  97260. $declarations[strtolower($namespaceUseAnalysis->getShortName())] = $namespaceUseAnalysis->getFullName();
  97261. }
  97262. $lowercaseName = strtolower($name);
  97263. foreach ($declarations as $lowercaseShortName => $fullName) {
  97264. if ($lowercaseName === $lowercaseShortName) {
  97265. return $fullName;
  97266. }
  97267. if (!str_starts_with($lowercaseName, $lowercaseShortName.'\\')) {
  97268. continue;
  97269. }
  97270. return $fullName.substr($name, \strlen($lowercaseShortName));
  97271. }
  97272. return $namespaceAnalysis->getFullName().'\\'.$name;
  97273. }
  97274. private function getNamespaceAnalysis(int $index): NamespaceAnalysis
  97275. {
  97276. foreach ($this->namespaceAnalyses as $namespace) {
  97277. if ($namespace->getScopeStartIndex() <= $index && $namespace->getScopeEndIndex() >= $index) {
  97278. return $namespace;
  97279. }
  97280. }
  97281. $namespace = (new NamespacesAnalyzer())->getNamespaceAt($this->tokens, $index);
  97282. $this->namespaceAnalyses[] = $namespace;
  97283. return $namespace;
  97284. }
  97285. }
  97286. <?php
  97287. declare(strict_types=1);
  97288. namespace PhpCsFixer\Tokenizer\Analyzer;
  97289. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  97290. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  97291. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  97292. use PhpCsFixer\Tokenizer\CT;
  97293. use PhpCsFixer\Tokenizer\FCT;
  97294. use PhpCsFixer\Tokenizer\Token;
  97295. use PhpCsFixer\Tokenizer\Tokens;
  97296. final class FunctionsAnalyzer
  97297. {
  97298. private const POSSIBLE_KINDS = [
  97299. T_DOUBLE_COLON, T_FUNCTION, CT::T_NAMESPACE_OPERATOR, T_NEW, CT::T_RETURN_REF, T_STRING, T_OBJECT_OPERATOR, FCT::T_NULLSAFE_OBJECT_OPERATOR, FCT::T_ATTRIBUTE];
  97300. private array $functionsAnalysis = ['tokens' => '', 'imports' => [], 'declarations' => []];
  97301. public function isGlobalFunctionCall(Tokens $tokens, int $index): bool
  97302. {
  97303. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  97304. return false;
  97305. }
  97306. $openParenthesisIndex = $tokens->getNextMeaningfulToken($index);
  97307. if (!$tokens[$openParenthesisIndex]->equals('(')) {
  97308. return false;
  97309. }
  97310. $previousIsNamespaceSeparator = false;
  97311. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  97312. if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
  97313. $previousIsNamespaceSeparator = true;
  97314. $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  97315. }
  97316. if ($tokens[$prevIndex]->isGivenKind(self::POSSIBLE_KINDS)) {
  97317. return false;
  97318. }
  97319. if ($tokens[$tokens->getNextMeaningfulToken($openParenthesisIndex)]->isGivenKind(CT::T_FIRST_CLASS_CALLABLE)) {
  97320. return false;
  97321. }
  97322. if ($previousIsNamespaceSeparator) {
  97323. return true;
  97324. }
  97325. $functionName = strtolower($tokens[$index]->getContent());
  97326. if ('set' === $functionName) {
  97327. if (!$tokens[$prevIndex]->equalsAny([[CT::T_PROPERTY_HOOK_BRACE_OPEN], ';', '}'])) {
  97328. return true;
  97329. }
  97330. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  97331. $afterCloseParenthesisIndex = $tokens->getNextMeaningfulToken($closeParenthesisIndex);
  97332. if ($tokens[$afterCloseParenthesisIndex]->equalsAny(['{', [T_DOUBLE_ARROW]])) {
  97333. return false;
  97334. }
  97335. }
  97336. if ($tokens->isChanged() || $tokens->getCodeHash() !== $this->functionsAnalysis['tokens']) {
  97337. $this->buildFunctionsAnalysis($tokens);
  97338. }
  97339. $scopeStartIndex = 0;
  97340. $scopeEndIndex = \count($tokens) - 1;
  97341. $inGlobalNamespace = false;
  97342. foreach ($tokens->getNamespaceDeclarations() as $declaration) {
  97343. $scopeStartIndex = $declaration->getScopeStartIndex();
  97344. $scopeEndIndex = $declaration->getScopeEndIndex();
  97345. if ($index >= $scopeStartIndex && $index <= $scopeEndIndex) {
  97346. $inGlobalNamespace = $declaration->isGlobalNamespace();
  97347. break;
  97348. }
  97349. }
  97350. if (!$inGlobalNamespace) {
  97351. foreach ($this->functionsAnalysis['declarations'] as $functionNameIndex) {
  97352. if ($functionNameIndex < $scopeStartIndex || $functionNameIndex > $scopeEndIndex) {
  97353. continue;
  97354. }
  97355. if (strtolower($tokens[$functionNameIndex]->getContent()) === $functionName) {
  97356. return false;
  97357. }
  97358. }
  97359. }
  97360. foreach ($this->functionsAnalysis['imports'] as $functionUse) {
  97361. if ($functionUse->getStartIndex() < $scopeStartIndex || $functionUse->getEndIndex() > $scopeEndIndex) {
  97362. continue;
  97363. }
  97364. if ($functionName !== strtolower($functionUse->getShortName())) {
  97365. continue;
  97366. }
  97367. return $functionUse->getShortName() === ltrim($functionUse->getFullName(), '\\');
  97368. }
  97369. if (AttributeAnalyzer::isAttribute($tokens, $index)) {
  97370. return false;
  97371. }
  97372. return true;
  97373. }
  97374. public function getFunctionArguments(Tokens $tokens, int $functionIndex): array
  97375. {
  97376. $argumentsStart = $tokens->getNextTokenOfKind($functionIndex, ['(']);
  97377. $argumentsEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStart);
  97378. $argumentAnalyzer = new ArgumentsAnalyzer();
  97379. $arguments = [];
  97380. foreach ($argumentAnalyzer->getArguments($tokens, $argumentsStart, $argumentsEnd) as $start => $end) {
  97381. $argumentInfo = $argumentAnalyzer->getArgumentInfo($tokens, $start, $end);
  97382. $arguments[$argumentInfo->getName()] = $argumentInfo;
  97383. }
  97384. return $arguments;
  97385. }
  97386. public function getFunctionReturnType(Tokens $tokens, int $methodIndex): ?TypeAnalysis
  97387. {
  97388. $argumentsStart = $tokens->getNextTokenOfKind($methodIndex, ['(']);
  97389. $argumentsEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $argumentsStart);
  97390. $typeColonIndex = $tokens->getNextMeaningfulToken($argumentsEnd);
  97391. if (!$tokens[$typeColonIndex]->isGivenKind(CT::T_TYPE_COLON)) {
  97392. return null;
  97393. }
  97394. $type = '';
  97395. $typeStartIndex = $tokens->getNextMeaningfulToken($typeColonIndex);
  97396. $typeEndIndex = $typeStartIndex;
  97397. $functionBodyStart = $tokens->getNextTokenOfKind($typeColonIndex, ['{', ';', [T_DOUBLE_ARROW]]);
  97398. for ($i = $typeStartIndex; $i < $functionBodyStart; ++$i) {
  97399. if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
  97400. continue;
  97401. }
  97402. $type .= $tokens[$i]->getContent();
  97403. $typeEndIndex = $i;
  97404. }
  97405. return new TypeAnalysis($type, $typeStartIndex, $typeEndIndex);
  97406. }
  97407. public function isTheSameClassCall(Tokens $tokens, int $index): bool
  97408. {
  97409. if (!$tokens->offsetExists($index)) {
  97410. throw new \InvalidArgumentException(\sprintf('Token index %d does not exist.', $index));
  97411. }
  97412. $operatorIndex = $tokens->getPrevMeaningfulToken($index);
  97413. if (null === $operatorIndex) {
  97414. return false;
  97415. }
  97416. if (!$tokens[$operatorIndex]->isObjectOperator() && !$tokens[$operatorIndex]->isGivenKind(T_DOUBLE_COLON)) {
  97417. return false;
  97418. }
  97419. $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
  97420. if (null === $referenceIndex) {
  97421. return false;
  97422. }
  97423. if (!$tokens[$referenceIndex]->equalsAny([[T_VARIABLE, '$this'], [T_STRING, 'self'], [T_STATIC, 'static']], false)) {
  97424. return false;
  97425. }
  97426. return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
  97427. }
  97428. private function buildFunctionsAnalysis(Tokens $tokens): void
  97429. {
  97430. $this->functionsAnalysis = [
  97431. 'tokens' => $tokens->getCodeHash(),
  97432. 'imports' => [],
  97433. 'declarations' => [],
  97434. ];
  97435. if ($tokens->isTokenKindFound(T_FUNCTION)) {
  97436. $end = \count($tokens);
  97437. for ($i = 0; $i < $end; ++$i) {
  97438. if ($tokens[$i]->isGivenKind(Token::getClassyTokenKinds())) {
  97439. $i = $tokens->getNextTokenOfKind($i, ['(', '{']);
  97440. if ($tokens[$i]->equals('(')) {
  97441. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
  97442. $i = $tokens->getNextTokenOfKind($i, ['{']);
  97443. }
  97444. $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);
  97445. continue;
  97446. }
  97447. if (!$tokens[$i]->isGivenKind(T_FUNCTION)) {
  97448. continue;
  97449. }
  97450. $i = $tokens->getNextMeaningfulToken($i);
  97451. if ($tokens[$i]->isGivenKind(CT::T_RETURN_REF)) {
  97452. $i = $tokens->getNextMeaningfulToken($i);
  97453. }
  97454. if (!$tokens[$i]->isGivenKind(T_STRING)) {
  97455. continue;
  97456. }
  97457. $this->functionsAnalysis['declarations'][] = $i;
  97458. }
  97459. }
  97460. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  97461. if ($tokens->isTokenKindFound(CT::T_FUNCTION_IMPORT)) {
  97462. $declarations = $namespaceUsesAnalyzer->getDeclarationsFromTokens($tokens);
  97463. foreach ($declarations as $declaration) {
  97464. if ($declaration->isFunction()) {
  97465. $this->functionsAnalysis['imports'][] = $declaration;
  97466. }
  97467. }
  97468. }
  97469. }
  97470. }
  97471. <?php
  97472. declare(strict_types=1);
  97473. namespace PhpCsFixer\Tokenizer\Analyzer;
  97474. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  97475. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  97476. use PhpCsFixer\Tokenizer\Tokens;
  97477. final class NamespacesAnalyzer
  97478. {
  97479. public function getDeclarations(Tokens $tokens): array
  97480. {
  97481. $namespaces = [];
  97482. for ($index = 1, $count = \count($tokens); $index < $count; ++$index) {
  97483. $token = $tokens[$index];
  97484. if (!$token->isGivenKind(T_NAMESPACE)) {
  97485. continue;
  97486. }
  97487. $declarationEndIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
  97488. $namespace = trim($tokens->generatePartialCode($index + 1, $declarationEndIndex - 1));
  97489. $declarationParts = explode('\\', $namespace);
  97490. $shortName = end($declarationParts);
  97491. if ($tokens[$declarationEndIndex]->equals('{')) {
  97492. $scopeEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $declarationEndIndex);
  97493. } else {
  97494. $scopeEndIndex = $tokens->getNextTokenOfKind($declarationEndIndex, [[T_NAMESPACE]]);
  97495. if (null === $scopeEndIndex) {
  97496. $scopeEndIndex = \count($tokens);
  97497. }
  97498. --$scopeEndIndex;
  97499. }
  97500. $namespaces[] = new NamespaceAnalysis(
  97501. $namespace,
  97502. $shortName,
  97503. $index,
  97504. $declarationEndIndex,
  97505. $index,
  97506. $scopeEndIndex
  97507. );
  97508. $index = $scopeEndIndex;
  97509. }
  97510. if (0 === \count($namespaces) && $tokens->isTokenKindFound(T_OPEN_TAG)) {
  97511. $namespaces[] = new NamespaceAnalysis(
  97512. '',
  97513. '',
  97514. $openTagIndex = $tokens[0]->isGivenKind(T_INLINE_HTML) ? 1 : 0,
  97515. $openTagIndex,
  97516. $openTagIndex,
  97517. \count($tokens) - 1,
  97518. );
  97519. }
  97520. return $namespaces;
  97521. }
  97522. public function getNamespaceAt(Tokens $tokens, int $index): NamespaceAnalysis
  97523. {
  97524. if (!$tokens->offsetExists($index)) {
  97525. throw new \InvalidArgumentException(\sprintf('Token index %d does not exist.', $index));
  97526. }
  97527. foreach ($this->getDeclarations($tokens) as $namespace) {
  97528. if ($namespace->getScopeStartIndex() <= $index && $namespace->getScopeEndIndex() >= $index) {
  97529. return $namespace;
  97530. }
  97531. }
  97532. throw new \LogicException(\sprintf('Unable to get the namespace at index %d.', $index));
  97533. }
  97534. public static function collectNamespaceAnalysis(Tokens $tokens, int $startIndex): array
  97535. {
  97536. $namespaceAnalysis = (new self())->getNamespaceAt($tokens, $startIndex);
  97537. $namespaceUseAnalyses = (new NamespaceUsesAnalyzer())->getDeclarationsInNamespace($tokens, $namespaceAnalysis);
  97538. $uses = [];
  97539. foreach ($namespaceUseAnalyses as $use) {
  97540. if (!$use->isClass()) {
  97541. continue;
  97542. }
  97543. $uses[$use->getShortName()] = $use;
  97544. }
  97545. return [$namespaceAnalysis, $uses];
  97546. }
  97547. }
  97548. <?php
  97549. declare(strict_types=1);
  97550. namespace PhpCsFixer\Tokenizer\Analyzer;
  97551. use PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis;
  97552. use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
  97553. use PhpCsFixer\Tokenizer\CT;
  97554. use PhpCsFixer\Tokenizer\FCT;
  97555. use PhpCsFixer\Tokenizer\Tokens;
  97556. final class ArgumentsAnalyzer
  97557. {
  97558. private const ARGUMENT_INFO_SKIP_TYPES = [T_ELLIPSIS, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  97559. public function countArguments(Tokens $tokens, int $openParenthesis, int $closeParenthesis): int
  97560. {
  97561. return \count($this->getArguments($tokens, $openParenthesis, $closeParenthesis));
  97562. }
  97563. public function getArguments(Tokens $tokens, int $openParenthesis, int $closeParenthesis): array
  97564. {
  97565. $arguments = [];
  97566. $firstSensibleToken = $tokens->getNextMeaningfulToken($openParenthesis);
  97567. if ($tokens[$firstSensibleToken]->equals(')')) {
  97568. return $arguments;
  97569. }
  97570. $paramContentIndex = $openParenthesis + 1;
  97571. $argumentsStart = $paramContentIndex;
  97572. for (; $paramContentIndex < $closeParenthesis; ++$paramContentIndex) {
  97573. $token = $tokens[$paramContentIndex];
  97574. $blockDefinitionProbe = Tokens::detectBlockType($token);
  97575. if (null !== $blockDefinitionProbe && true === $blockDefinitionProbe['isStart']) {
  97576. $paramContentIndex = $tokens->findBlockEnd($blockDefinitionProbe['type'], $paramContentIndex);
  97577. continue;
  97578. }
  97579. if ($token->equals(',')) {
  97580. if ($tokens->getNextMeaningfulToken($paramContentIndex) === $closeParenthesis) {
  97581. break;
  97582. }
  97583. $arguments[$argumentsStart] = $paramContentIndex - 1;
  97584. $argumentsStart = $paramContentIndex + 1;
  97585. }
  97586. }
  97587. $arguments[$argumentsStart] = $paramContentIndex - 1;
  97588. return $arguments;
  97589. }
  97590. public function getArgumentInfo(Tokens $tokens, int $argumentStart, int $argumentEnd): ArgumentAnalysis
  97591. {
  97592. $info = [
  97593. 'default' => null,
  97594. 'name' => null,
  97595. 'name_index' => null,
  97596. 'type' => null,
  97597. 'type_index_start' => null,
  97598. 'type_index_end' => null,
  97599. ];
  97600. $sawName = false;
  97601. for ($index = $argumentStart; $index <= $argumentEnd; ++$index) {
  97602. $token = $tokens[$index];
  97603. if ($token->isGivenKind(FCT::T_ATTRIBUTE)) {
  97604. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  97605. continue;
  97606. }
  97607. if (
  97608. $token->isComment()
  97609. || $token->isWhitespace()
  97610. || $token->isGivenKind(self::ARGUMENT_INFO_SKIP_TYPES)
  97611. || $token->equals('&')
  97612. ) {
  97613. continue;
  97614. }
  97615. if ($token->isGivenKind(T_VARIABLE)) {
  97616. $sawName = true;
  97617. $info['name_index'] = $index;
  97618. $info['name'] = $token->getContent();
  97619. continue;
  97620. }
  97621. if ($token->equals('=')) {
  97622. continue;
  97623. }
  97624. if ($sawName) {
  97625. $info['default'] .= $token->getContent();
  97626. } else {
  97627. $info['type_index_start'] = ($info['type_index_start'] > 0) ? $info['type_index_start'] : $index;
  97628. $info['type_index_end'] = $index;
  97629. $info['type'] .= $token->getContent();
  97630. }
  97631. }
  97632. if (null === $info['name']) {
  97633. $info['type'] = null;
  97634. }
  97635. return new ArgumentAnalysis(
  97636. $info['name'],
  97637. $info['name_index'],
  97638. $info['default'],
  97639. null !== $info['type'] ? new TypeAnalysis($info['type'], $info['type_index_start'], $info['type_index_end']) : null
  97640. );
  97641. }
  97642. }
  97643. <?php
  97644. declare(strict_types=1);
  97645. namespace PhpCsFixer\Tokenizer\Analyzer;
  97646. use PhpCsFixer\Tokenizer\Tokens;
  97647. final class AlternativeSyntaxAnalyzer
  97648. {
  97649. private const ALTERNATIVE_SYNTAX_BLOCK_EDGES = [
  97650. T_IF => [T_ENDIF, T_ELSE, T_ELSEIF],
  97651. T_ELSE => [T_ENDIF],
  97652. T_ELSEIF => [T_ENDIF, T_ELSE, T_ELSEIF],
  97653. T_FOR => [T_ENDFOR],
  97654. T_FOREACH => [T_ENDFOREACH],
  97655. T_WHILE => [T_ENDWHILE],
  97656. T_SWITCH => [T_ENDSWITCH],
  97657. ];
  97658. public function belongsToAlternativeSyntax(Tokens $tokens, int $index): bool
  97659. {
  97660. if (!$tokens[$index]->equals(':')) {
  97661. return false;
  97662. }
  97663. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  97664. if ($tokens[$prevIndex]->isGivenKind(T_ELSE)) {
  97665. return true;
  97666. }
  97667. if (!$tokens[$prevIndex]->equals(')')) {
  97668. return false;
  97669. }
  97670. $openParenthesisIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevIndex);
  97671. $beforeOpenParenthesisIndex = $tokens->getPrevMeaningfulToken($openParenthesisIndex);
  97672. return $tokens[$beforeOpenParenthesisIndex]->isGivenKind([
  97673. T_DECLARE,
  97674. T_ELSEIF,
  97675. T_FOR,
  97676. T_FOREACH,
  97677. T_IF,
  97678. T_SWITCH,
  97679. T_WHILE,
  97680. ]);
  97681. }
  97682. public function findAlternativeSyntaxBlockEnd(Tokens $tokens, int $index): int
  97683. {
  97684. if (!isset($tokens[$index])) {
  97685. throw new \InvalidArgumentException("There is no token at index {$index}.");
  97686. }
  97687. if (!$this->isStartOfAlternativeSyntaxBlock($tokens, $index)) {
  97688. throw new \InvalidArgumentException("Token at index {$index} is not the start of an alternative syntax block.");
  97689. }
  97690. $startTokenKind = $tokens[$index]->getId();
  97691. if (!isset(self::ALTERNATIVE_SYNTAX_BLOCK_EDGES[$startTokenKind])) {
  97692. throw new \LogicException(\sprintf('Unknown startTokenKind: %s', $tokens[$index]->toJson()));
  97693. }
  97694. $endTokenKinds = self::ALTERNATIVE_SYNTAX_BLOCK_EDGES[$startTokenKind];
  97695. $findKinds = [[$startTokenKind]];
  97696. foreach ($endTokenKinds as $endTokenKind) {
  97697. $findKinds[] = [$endTokenKind];
  97698. }
  97699. while (true) {
  97700. $index = $tokens->getNextTokenOfKind($index, $findKinds);
  97701. if ($tokens[$index]->isGivenKind($endTokenKinds)) {
  97702. return $index;
  97703. }
  97704. if ($this->isStartOfAlternativeSyntaxBlock($tokens, $index)) {
  97705. $index = $this->findAlternativeSyntaxBlockEnd($tokens, $index);
  97706. }
  97707. }
  97708. }
  97709. private function isStartOfAlternativeSyntaxBlock(Tokens $tokens, int $index): bool
  97710. {
  97711. $map = self::ALTERNATIVE_SYNTAX_BLOCK_EDGES;
  97712. $startTokenKind = $tokens[$index]->getId();
  97713. if (null === $startTokenKind || !isset($map[$startTokenKind])) {
  97714. return false;
  97715. }
  97716. $index = $tokens->getNextMeaningfulToken($index);
  97717. if ($tokens[$index]->equals('(')) {
  97718. $index = $tokens->getNextMeaningfulToken(
  97719. $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index)
  97720. );
  97721. }
  97722. return $tokens[$index]->equals(':');
  97723. }
  97724. }
  97725. <?php
  97726. declare(strict_types=1);
  97727. namespace PhpCsFixer\Tokenizer\Analyzer;
  97728. use PhpCsFixer\Tokenizer\CT;
  97729. use PhpCsFixer\Tokenizer\Tokens;
  97730. final class RangeAnalyzer
  97731. {
  97732. private function __construct()
  97733. {
  97734. }
  97735. public static function rangeEqualsRange(Tokens $tokens, array $range1, array $range2): bool
  97736. {
  97737. $leftStart = $range1['start'];
  97738. $leftEnd = $range1['end'];
  97739. if ($tokens[$leftStart]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  97740. $leftStart = $tokens->getNextMeaningfulToken($leftStart);
  97741. }
  97742. while ($tokens[$leftStart]->equals('(') && $tokens[$leftEnd]->equals(')')) {
  97743. $leftStart = $tokens->getNextMeaningfulToken($leftStart);
  97744. $leftEnd = $tokens->getPrevMeaningfulToken($leftEnd);
  97745. }
  97746. $rightStart = $range2['start'];
  97747. $rightEnd = $range2['end'];
  97748. if ($tokens[$rightStart]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
  97749. $rightStart = $tokens->getNextMeaningfulToken($rightStart);
  97750. }
  97751. while ($tokens[$rightStart]->equals('(') && $tokens[$rightEnd]->equals(')')) {
  97752. $rightStart = $tokens->getNextMeaningfulToken($rightStart);
  97753. $rightEnd = $tokens->getPrevMeaningfulToken($rightEnd);
  97754. }
  97755. $arrayOpenTypes = ['[', [CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN]];
  97756. $arrayCloseTypes = [']', [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE]];
  97757. while (true) {
  97758. $leftToken = $tokens[$leftStart];
  97759. $rightToken = $tokens[$rightStart];
  97760. if (
  97761. !$leftToken->equals($rightToken)
  97762. && !($leftToken->equalsAny($arrayOpenTypes) && $rightToken->equalsAny($arrayOpenTypes))
  97763. && !($leftToken->equalsAny($arrayCloseTypes) && $rightToken->equalsAny($arrayCloseTypes))
  97764. ) {
  97765. return false;
  97766. }
  97767. $leftStart = $tokens->getNextMeaningfulToken($leftStart);
  97768. $rightStart = $tokens->getNextMeaningfulToken($rightStart);
  97769. $reachedLeftEnd = null === $leftStart || $leftStart > $leftEnd;
  97770. $reachedRightEnd = null === $rightStart || $rightStart > $rightEnd;
  97771. if (!$reachedLeftEnd && !$reachedRightEnd) {
  97772. continue;
  97773. }
  97774. return $reachedLeftEnd && $reachedRightEnd;
  97775. }
  97776. }
  97777. }
  97778. <?php
  97779. declare(strict_types=1);
  97780. namespace PhpCsFixer\Tokenizer\Analyzer;
  97781. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  97782. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  97783. use PhpCsFixer\Tokenizer\CT;
  97784. use PhpCsFixer\Tokenizer\Tokens;
  97785. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  97786. final class NamespaceUsesAnalyzer
  97787. {
  97788. public function getDeclarationsFromTokens(Tokens $tokens, bool $allowMultiUses = false): array
  97789. {
  97790. $tokenAnalyzer = new TokensAnalyzer($tokens);
  97791. $useIndices = $tokenAnalyzer->getImportUseIndexes();
  97792. return $this->getDeclarations($tokens, $useIndices, $allowMultiUses);
  97793. }
  97794. public function getDeclarationsInNamespace(Tokens $tokens, NamespaceAnalysis $namespace, bool $allowMultiUses = false): array
  97795. {
  97796. $namespaceUses = [];
  97797. foreach ($this->getDeclarationsFromTokens($tokens, $allowMultiUses) as $namespaceUse) {
  97798. if ($namespaceUse->getStartIndex() >= $namespace->getScopeStartIndex() && $namespaceUse->getStartIndex() <= $namespace->getScopeEndIndex()) {
  97799. $namespaceUses[] = $namespaceUse;
  97800. }
  97801. }
  97802. return $namespaceUses;
  97803. }
  97804. private function getDeclarations(Tokens $tokens, array $useIndices, bool $allowMultiUses = false): array
  97805. {
  97806. $uses = [];
  97807. foreach ($useIndices as $index) {
  97808. $endIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
  97809. $declarations = $this->parseDeclarations($index, $endIndex, $tokens);
  97810. if (false === $allowMultiUses) {
  97811. $declarations = array_filter($declarations, static fn (NamespaceUseAnalysis $declaration) => !$declaration->isInMulti());
  97812. }
  97813. if ([] !== $declarations) {
  97814. $uses = array_merge($uses, $declarations);
  97815. }
  97816. }
  97817. return $uses;
  97818. }
  97819. private function parseDeclarations(int $startIndex, int $endIndex, Tokens $tokens): array
  97820. {
  97821. $type = $this->determineImportType($tokens, $startIndex);
  97822. $potentialMulti = $tokens->getNextTokenOfKind($startIndex, [',', [CT::T_GROUP_IMPORT_BRACE_OPEN]]);
  97823. $multi = null !== $potentialMulti && $potentialMulti < $endIndex;
  97824. $index = $tokens->getNextTokenOfKind($startIndex, [[T_STRING], [T_NS_SEPARATOR]]);
  97825. $imports = [];
  97826. while (null !== $index && $index <= $endIndex) {
  97827. $qualifiedName = $this->getNearestQualifiedName($tokens, $index);
  97828. $token = $tokens[$qualifiedName['afterIndex']];
  97829. if ($token->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
  97830. $groupStart = $groupIndex = $qualifiedName['afterIndex'];
  97831. $groupEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $groupStart);
  97832. while ($groupIndex < $groupEnd) {
  97833. $chunkStart = $tokens->getNextMeaningfulToken($groupIndex);
  97834. if ($tokens[$chunkStart]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  97835. break;
  97836. }
  97837. $groupQualifiedName = $this->getNearestQualifiedName($tokens, $chunkStart);
  97838. $imports[] = new NamespaceUseAnalysis(
  97839. $type,
  97840. $qualifiedName['fullName'].$groupQualifiedName['fullName'],
  97841. $groupQualifiedName['shortName'],
  97842. $groupQualifiedName['aliased'],
  97843. true,
  97844. $startIndex,
  97845. $endIndex,
  97846. $chunkStart,
  97847. $tokens->getPrevMeaningfulToken($groupQualifiedName['afterIndex'])
  97848. );
  97849. $groupIndex = $groupQualifiedName['afterIndex'];
  97850. }
  97851. $index = $groupIndex;
  97852. } elseif ($token->equalsAny([',', ';', [T_CLOSE_TAG]])) {
  97853. $previousToken = $tokens->getPrevMeaningfulToken($qualifiedName['afterIndex']);
  97854. if (!$tokens[$previousToken]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
  97855. $imports[] = new NamespaceUseAnalysis(
  97856. $type,
  97857. $qualifiedName['fullName'],
  97858. $qualifiedName['shortName'],
  97859. $qualifiedName['aliased'],
  97860. $multi,
  97861. $startIndex,
  97862. $endIndex,
  97863. $multi ? $index : null,
  97864. $multi ? $previousToken : null
  97865. );
  97866. }
  97867. $index = $qualifiedName['afterIndex'];
  97868. }
  97869. $index = $tokens->getNextMeaningfulToken($index);
  97870. }
  97871. return $imports;
  97872. }
  97873. private function determineImportType(Tokens $tokens, int $startIndex): int
  97874. {
  97875. $potentialType = $tokens[$tokens->getNextMeaningfulToken($startIndex)];
  97876. if ($potentialType->isGivenKind(CT::T_FUNCTION_IMPORT)) {
  97877. return NamespaceUseAnalysis::TYPE_FUNCTION;
  97878. }
  97879. if ($potentialType->isGivenKind(CT::T_CONST_IMPORT)) {
  97880. return NamespaceUseAnalysis::TYPE_CONSTANT;
  97881. }
  97882. return NamespaceUseAnalysis::TYPE_CLASS;
  97883. }
  97884. private function getNearestQualifiedName(Tokens $tokens, int $index): array
  97885. {
  97886. $fullName = $shortName = '';
  97887. $aliased = false;
  97888. while (null !== $index) {
  97889. $token = $tokens[$index];
  97890. if ($token->isGivenKind(T_STRING)) {
  97891. $shortName = $token->getContent();
  97892. if (!$aliased) {
  97893. $fullName .= $shortName;
  97894. }
  97895. } elseif ($token->isGivenKind(T_NS_SEPARATOR)) {
  97896. $fullName .= $token->getContent();
  97897. } elseif ($token->isGivenKind(T_AS)) {
  97898. $aliased = true;
  97899. } elseif ($token->equalsAny([
  97900. ',',
  97901. ';',
  97902. [CT::T_GROUP_IMPORT_BRACE_OPEN],
  97903. [CT::T_GROUP_IMPORT_BRACE_CLOSE],
  97904. [T_CLOSE_TAG],
  97905. ])) {
  97906. break;
  97907. }
  97908. $index = $tokens->getNextMeaningfulToken($index);
  97909. }
  97910. $fqn = $fullName;
  97911. return [
  97912. 'fullName' => $fqn,
  97913. 'shortName' => $shortName,
  97914. 'aliased' => $aliased,
  97915. 'afterIndex' => $index,
  97916. ];
  97917. }
  97918. }
  97919. <?php
  97920. declare(strict_types=1);
  97921. namespace PhpCsFixer\Tokenizer\Analyzer;
  97922. use PhpCsFixer\Tokenizer\CT;
  97923. use PhpCsFixer\Tokenizer\Tokens;
  97924. final class ClassyAnalyzer
  97925. {
  97926. public function isClassyInvocation(Tokens $tokens, int $index): bool
  97927. {
  97928. $token = $tokens[$index];
  97929. if (!$token->isGivenKind(T_STRING)) {
  97930. throw new \LogicException(\sprintf('No T_STRING at given index %d, got "%s".', $index, $tokens[$index]->getName()));
  97931. }
  97932. if ((new Analysis\TypeAnalysis($token->getContent()))->isReservedType()) {
  97933. return false;
  97934. }
  97935. $next = $tokens->getNextMeaningfulToken($index);
  97936. $nextToken = $tokens[$next];
  97937. if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
  97938. return false;
  97939. }
  97940. if ($nextToken->isGivenKind([T_DOUBLE_COLON, T_ELLIPSIS, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, T_VARIABLE])) {
  97941. return true;
  97942. }
  97943. $prev = $tokens->getPrevMeaningfulToken($index);
  97944. while ($tokens[$prev]->isGivenKind([CT::T_NAMESPACE_OPERATOR, T_NS_SEPARATOR, T_STRING])) {
  97945. $prev = $tokens->getPrevMeaningfulToken($prev);
  97946. }
  97947. $prevToken = $tokens[$prev];
  97948. if ($prevToken->isGivenKind([T_EXTENDS, T_INSTANCEOF, T_INSTEADOF, T_IMPLEMENTS, T_NEW, CT::T_NULLABLE_TYPE, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, CT::T_TYPE_COLON, CT::T_USE_TRAIT])) {
  97949. return true;
  97950. }
  97951. if (\PHP_VERSION_ID >= 8_00_00 && $nextToken->equals(')') && $prevToken->equals('(') && $tokens[$tokens->getPrevMeaningfulToken($prev)]->isGivenKind(T_CATCH)) {
  97952. return true;
  97953. }
  97954. if (AttributeAnalyzer::isAttribute($tokens, $index)) {
  97955. return true;
  97956. }
  97957. if ($nextToken->equals('&') && $tokens[$tokens->getNextMeaningfulToken($next)]->isGivenKind(T_VARIABLE)) {
  97958. $checkIndex = $tokens->getPrevTokenOfKind($prev + 1, [';', '{', '}', [T_FUNCTION], [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]);
  97959. return $tokens[$checkIndex]->isGivenKind(T_FUNCTION);
  97960. }
  97961. if (!$prevToken->equals(',')) {
  97962. return false;
  97963. }
  97964. do {
  97965. $prev = $tokens->getPrevMeaningfulToken($prev);
  97966. } while ($tokens[$prev]->equalsAny([',', [T_NS_SEPARATOR], [T_STRING], [CT::T_NAMESPACE_OPERATOR]]));
  97967. return $tokens[$prev]->isGivenKind([T_IMPLEMENTS, CT::T_USE_TRAIT]);
  97968. }
  97969. }
  97970. <?php
  97971. declare(strict_types=1);
  97972. namespace PhpCsFixer\Tokenizer\Analyzer;
  97973. use PhpCsFixer\Tokenizer\Analyzer\Analysis\SwitchAnalysis;
  97974. use PhpCsFixer\Tokenizer\Tokens;
  97975. final class SwitchAnalyzer
  97976. {
  97977. private static array $cache = [];
  97978. public static function belongsToSwitch(Tokens $tokens, int $index): bool
  97979. {
  97980. if (!$tokens[$index]->equals(':')) {
  97981. return false;
  97982. }
  97983. $collectionHash = $tokens->getCollectionHash();
  97984. if (!\array_key_exists($collectionHash, self::$cache)) {
  97985. self::$cache[$collectionHash] = self::getColonIndicesForSwitch(clone $tokens);
  97986. }
  97987. $arr = self::$cache[$collectionHash];
  97988. return \in_array($index, $arr, true);
  97989. }
  97990. private static function getColonIndicesForSwitch(Tokens $tokens): array
  97991. {
  97992. $colonIndices = [];
  97993. foreach (ControlCaseStructuresAnalyzer::findControlStructures($tokens, [T_SWITCH]) as $analysis) {
  97994. if ($tokens[$analysis->getOpenIndex()]->equals(':')) {
  97995. $colonIndices[] = $analysis->getOpenIndex();
  97996. }
  97997. foreach ($analysis->getCases() as $case) {
  97998. $colonIndices[] = $case->getColonIndex();
  97999. }
  98000. $defaultAnalysis = $analysis->getDefaultAnalysis();
  98001. if (null !== $defaultAnalysis) {
  98002. $colonIndices[] = $defaultAnalysis->getColonIndex();
  98003. }
  98004. }
  98005. return $colonIndices;
  98006. }
  98007. }
  98008. <?php
  98009. declare(strict_types=1);
  98010. namespace PhpCsFixer\Tokenizer\Analyzer;
  98011. use PhpCsFixer\Preg;
  98012. use PhpCsFixer\Tokenizer\Tokens;
  98013. final class PhpUnitTestCaseAnalyzer
  98014. {
  98015. public function findPhpUnitClasses(Tokens $tokens): iterable
  98016. {
  98017. for ($index = $tokens->count() - 1; $index > 0; --$index) {
  98018. if (!$this->isPhpUnitClass($tokens, $index)) {
  98019. continue;
  98020. }
  98021. $startIndex = $tokens->getNextTokenOfKind($index, ['{']);
  98022. \assert(\is_int($startIndex));
  98023. $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
  98024. yield [$startIndex, $endIndex];
  98025. }
  98026. }
  98027. private function isPhpUnitClass(Tokens $tokens, int $index): bool
  98028. {
  98029. if (!$tokens[$index]->isGivenKind(T_CLASS)) {
  98030. return false;
  98031. }
  98032. $extendsIndex = $tokens->getNextTokenOfKind($index, ['{', [T_EXTENDS]]);
  98033. if (!$tokens[$extendsIndex]->isGivenKind(T_EXTENDS)) {
  98034. return false;
  98035. }
  98036. if (Preg::match('/(?:Test|TestCase)$/', $tokens[$index]->getContent())) {
  98037. return true;
  98038. }
  98039. while (null !== $index = $tokens->getNextMeaningfulToken($index)) {
  98040. if ($tokens[$index]->equals('{')) {
  98041. break;
  98042. }
  98043. if (!$tokens[$index]->isGivenKind(T_STRING)) {
  98044. continue;
  98045. }
  98046. if (Preg::match('/(?:Test|TestCase)(?:Interface)?$/', $tokens[$index]->getContent())) {
  98047. return true;
  98048. }
  98049. }
  98050. return false;
  98051. }
  98052. }
  98053. <?php
  98054. declare(strict_types=1);
  98055. namespace PhpCsFixer\Tokenizer\Analyzer;
  98056. use PhpCsFixer\Tokenizer\Tokens;
  98057. final class WhitespacesAnalyzer
  98058. {
  98059. public static function detectIndent(Tokens $tokens, int $index): string
  98060. {
  98061. while (true) {
  98062. $whitespaceIndex = $tokens->getPrevTokenOfKind($index, [[T_WHITESPACE]]);
  98063. if (null === $whitespaceIndex) {
  98064. return '';
  98065. }
  98066. $whitespaceToken = $tokens[$whitespaceIndex];
  98067. if (str_contains($whitespaceToken->getContent(), "\n")) {
  98068. break;
  98069. }
  98070. $prevToken = $tokens[$whitespaceIndex - 1];
  98071. if ($prevToken->isGivenKind([T_OPEN_TAG, T_COMMENT]) && "\n" === substr($prevToken->getContent(), -1)) {
  98072. break;
  98073. }
  98074. $index = $whitespaceIndex;
  98075. }
  98076. $explodedContent = explode("\n", $whitespaceToken->getContent());
  98077. return end($explodedContent);
  98078. }
  98079. }
  98080. <?php
  98081. declare(strict_types=1);
  98082. namespace PhpCsFixer\Tokenizer\Analyzer;
  98083. use PhpCsFixer\Preg;
  98084. use PhpCsFixer\Tokenizer\CT;
  98085. use PhpCsFixer\Tokenizer\FCT;
  98086. use PhpCsFixer\Tokenizer\Token;
  98087. use PhpCsFixer\Tokenizer\Tokens;
  98088. final class CommentsAnalyzer
  98089. {
  98090. private const TYPE_HASH = 1;
  98091. private const TYPE_DOUBLE_SLASH = 2;
  98092. private const TYPE_SLASH_ASTERISK = 3;
  98093. private const SKIP_TYPES = [
  98094. T_PRIVATE,
  98095. T_PROTECTED,
  98096. T_PUBLIC,
  98097. T_VAR,
  98098. T_FUNCTION,
  98099. T_FN,
  98100. T_ABSTRACT,
  98101. T_CONST,
  98102. T_NAMESPACE,
  98103. T_REQUIRE,
  98104. T_REQUIRE_ONCE,
  98105. T_INCLUDE,
  98106. T_INCLUDE_ONCE,
  98107. T_FINAL,
  98108. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
  98109. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
  98110. CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
  98111. FCT::T_READONLY,
  98112. FCT::T_PUBLIC_SET,
  98113. FCT::T_PROTECTED_SET,
  98114. FCT::T_PRIVATE_SET,
  98115. ];
  98116. public function isHeaderComment(Tokens $tokens, int $index): bool
  98117. {
  98118. if (!$tokens[$index]->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  98119. throw new \InvalidArgumentException('Given index must point to a comment.');
  98120. }
  98121. if (null === $tokens->getNextMeaningfulToken($index)) {
  98122. return false;
  98123. }
  98124. $prevIndex = $tokens->getPrevNonWhitespace($index);
  98125. if ($tokens[$prevIndex]->equals(';')) {
  98126. $braceCloseIndex = $tokens->getPrevMeaningfulToken($prevIndex);
  98127. if (!$tokens[$braceCloseIndex]->equals(')')) {
  98128. return false;
  98129. }
  98130. $braceOpenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceCloseIndex);
  98131. $declareIndex = $tokens->getPrevMeaningfulToken($braceOpenIndex);
  98132. if (!$tokens[$declareIndex]->isGivenKind(T_DECLARE)) {
  98133. return false;
  98134. }
  98135. $prevIndex = $tokens->getPrevNonWhitespace($declareIndex);
  98136. }
  98137. return $tokens[$prevIndex]->isGivenKind(T_OPEN_TAG);
  98138. }
  98139. public function isBeforeStructuralElement(Tokens $tokens, int $index): bool
  98140. {
  98141. $token = $tokens[$index];
  98142. if (!$token->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  98143. throw new \InvalidArgumentException('Given index must point to a comment.');
  98144. }
  98145. $nextIndex = $this->getNextTokenIndex($tokens, $index);
  98146. if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
  98147. return false;
  98148. }
  98149. if ($this->isStructuralElement($tokens, $nextIndex)) {
  98150. return true;
  98151. }
  98152. if ($this->isValidControl($tokens, $token, $nextIndex)) {
  98153. return true;
  98154. }
  98155. if ($this->isValidVariable($tokens, $nextIndex)) {
  98156. return true;
  98157. }
  98158. if ($this->isValidVariableAssignment($tokens, $token, $nextIndex)) {
  98159. return true;
  98160. }
  98161. if ($tokens[$nextIndex]->isGivenKind(CT::T_USE_TRAIT)) {
  98162. return true;
  98163. }
  98164. return false;
  98165. }
  98166. public function isBeforeReturn(Tokens $tokens, int $index): bool
  98167. {
  98168. if (!$tokens[$index]->isGivenKind([T_COMMENT, T_DOC_COMMENT])) {
  98169. throw new \InvalidArgumentException('Given index must point to a comment.');
  98170. }
  98171. $nextIndex = $this->getNextTokenIndex($tokens, $index);
  98172. if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
  98173. return false;
  98174. }
  98175. return $tokens[$nextIndex]->isGivenKind(T_RETURN);
  98176. }
  98177. public function getCommentBlockIndices(Tokens $tokens, int $index): array
  98178. {
  98179. if (!$tokens[$index]->isGivenKind(T_COMMENT)) {
  98180. throw new \InvalidArgumentException('Given index must point to a comment.');
  98181. }
  98182. $commentType = $this->getCommentType($tokens[$index]->getContent());
  98183. $indices = [$index];
  98184. if (self::TYPE_SLASH_ASTERISK === $commentType) {
  98185. return $indices;
  98186. }
  98187. $count = \count($tokens);
  98188. ++$index;
  98189. for (; $index < $count; ++$index) {
  98190. if ($tokens[$index]->isComment()) {
  98191. if ($commentType === $this->getCommentType($tokens[$index]->getContent())) {
  98192. $indices[] = $index;
  98193. continue;
  98194. }
  98195. break;
  98196. }
  98197. if (!$tokens[$index]->isWhitespace() || $this->getLineBreakCount($tokens, $index, $index + 1) > 1) {
  98198. break;
  98199. }
  98200. }
  98201. return $indices;
  98202. }
  98203. private function isStructuralElement(Tokens $tokens, int $index): bool
  98204. {
  98205. $token = $tokens[$index];
  98206. if ($token->isClassy() || $token->isGivenKind(self::SKIP_TYPES)) {
  98207. return true;
  98208. }
  98209. if ($token->isGivenKind(T_CASE)) {
  98210. $enumParent = $tokens->getPrevTokenOfKind($index, [[FCT::T_ENUM], [T_SWITCH]]);
  98211. return $tokens[$enumParent]->isGivenKind([FCT::T_ENUM]);
  98212. }
  98213. if ($token->isGivenKind(T_STATIC)) {
  98214. return !$tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_DOUBLE_COLON);
  98215. }
  98216. return false;
  98217. }
  98218. private function isValidControl(Tokens $tokens, Token $docsToken, int $controlIndex): bool
  98219. {
  98220. static $controlStructures = [
  98221. T_FOR,
  98222. T_FOREACH,
  98223. T_IF,
  98224. T_SWITCH,
  98225. T_WHILE,
  98226. ];
  98227. if (!$tokens[$controlIndex]->isGivenKind($controlStructures)) {
  98228. return false;
  98229. }
  98230. $openParenthesisIndex = $tokens->getNextMeaningfulToken($controlIndex);
  98231. $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex);
  98232. $docsContent = $docsToken->getContent();
  98233. for ($index = $openParenthesisIndex + 1; $index < $closeParenthesisIndex; ++$index) {
  98234. $token = $tokens[$index];
  98235. if (
  98236. $token->isGivenKind(T_VARIABLE)
  98237. && str_contains($docsContent, $token->getContent())
  98238. ) {
  98239. return true;
  98240. }
  98241. }
  98242. return false;
  98243. }
  98244. private function isValidVariableAssignment(Tokens $tokens, Token $docsToken, int $languageConstructIndex): bool
  98245. {
  98246. static $languageStructures = [
  98247. T_LIST,
  98248. T_PRINT,
  98249. T_ECHO,
  98250. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  98251. ];
  98252. if (!$tokens[$languageConstructIndex]->isGivenKind($languageStructures)) {
  98253. return false;
  98254. }
  98255. $endKind = $tokens[$languageConstructIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)
  98256. ? [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]
  98257. : ')';
  98258. $endIndex = $tokens->getNextTokenOfKind($languageConstructIndex, [$endKind]);
  98259. $docsContent = $docsToken->getContent();
  98260. for ($index = $languageConstructIndex + 1; $index < $endIndex; ++$index) {
  98261. $token = $tokens[$index];
  98262. if ($token->isGivenKind(T_VARIABLE) && str_contains($docsContent, $token->getContent())) {
  98263. return true;
  98264. }
  98265. }
  98266. return false;
  98267. }
  98268. private function isValidVariable(Tokens $tokens, int $index): bool
  98269. {
  98270. static $assignmentTypes = [
  98271. '=',
  98272. [T_PLUS_EQUAL, '+='],
  98273. [T_MINUS_EQUAL, '-='],
  98274. [T_MUL_EQUAL, '*='],
  98275. [T_DIV_EQUAL, '/='],
  98276. [T_MOD_EQUAL, '%='],
  98277. [T_POW_EQUAL, '**='],
  98278. [T_AND_EQUAL, '&='],
  98279. [T_OR_EQUAL, '|='],
  98280. [T_XOR_EQUAL, '^='],
  98281. [T_SL_EQUAL, '<<='],
  98282. [T_SR_EQUAL, '>>='],
  98283. [T_COALESCE_EQUAL, '??='],
  98284. [T_CONCAT_EQUAL, '.='],
  98285. ];
  98286. if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
  98287. return false;
  98288. }
  98289. $nextIndex = $tokens->getNextMeaningfulToken($index);
  98290. return $tokens[$nextIndex]->equalsAny($assignmentTypes);
  98291. }
  98292. private function getCommentType(string $content): int
  98293. {
  98294. if (str_starts_with($content, '#')) {
  98295. return self::TYPE_HASH;
  98296. }
  98297. if ('*' === $content[1]) {
  98298. return self::TYPE_SLASH_ASTERISK;
  98299. }
  98300. return self::TYPE_DOUBLE_SLASH;
  98301. }
  98302. private function getLineBreakCount(Tokens $tokens, int $whiteStart, int $whiteEnd): int
  98303. {
  98304. $lineCount = 0;
  98305. for ($i = $whiteStart; $i < $whiteEnd; ++$i) {
  98306. $lineCount += Preg::matchAll('/\R/u', $tokens[$i]->getContent());
  98307. }
  98308. return $lineCount;
  98309. }
  98310. private function getNextTokenIndex(Tokens $tokens, int $startIndex): ?int
  98311. {
  98312. $nextIndex = $startIndex;
  98313. do {
  98314. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  98315. while (null !== $nextIndex && $tokens[$nextIndex]->isGivenKind(FCT::T_ATTRIBUTE)) {
  98316. $nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $nextIndex);
  98317. $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
  98318. }
  98319. } while (null !== $nextIndex && $tokens[$nextIndex]->equals('('));
  98320. return $nextIndex;
  98321. }
  98322. }
  98323. <?php
  98324. declare(strict_types=1);
  98325. namespace PhpCsFixer\Tokenizer\Analyzer;
  98326. use PhpCsFixer\Preg;
  98327. use PhpCsFixer\Tokenizer\Analyzer\Analysis\AttributeAnalysis;
  98328. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  98329. use PhpCsFixer\Tokenizer\CT;
  98330. use PhpCsFixer\Tokenizer\FCT;
  98331. use PhpCsFixer\Tokenizer\Tokens;
  98332. /**
  98333. @phpstan-import-type
  98334. */
  98335. final class AttributeAnalyzer
  98336. {
  98337. private const TOKEN_KINDS_NOT_ALLOWED_IN_ATTRIBUTE = [
  98338. ';',
  98339. '{',
  98340. [T_ATTRIBUTE],
  98341. [T_FUNCTION],
  98342. [T_OPEN_TAG],
  98343. [T_OPEN_TAG_WITH_ECHO],
  98344. [T_PRIVATE],
  98345. [T_PROTECTED],
  98346. [T_PUBLIC],
  98347. [T_RETURN],
  98348. [T_VARIABLE],
  98349. [CT::T_ATTRIBUTE_CLOSE],
  98350. ];
  98351. public static function isAttribute(Tokens $tokens, int $index): bool
  98352. {
  98353. if (
  98354. !$tokens[$index]->isGivenKind(T_STRING)
  98355. || !$tokens->isAnyTokenKindsFound([FCT::T_ATTRIBUTE])
  98356. ) {
  98357. return false;
  98358. }
  98359. $attributeStartIndex = $tokens->getPrevTokenOfKind($index, self::TOKEN_KINDS_NOT_ALLOWED_IN_ATTRIBUTE);
  98360. if (!$tokens[$attributeStartIndex]->isGivenKind(T_ATTRIBUTE)) {
  98361. return false;
  98362. }
  98363. $count = 0;
  98364. for ($i = $attributeStartIndex + 1; $i < $index; ++$i) {
  98365. if ($tokens[$i]->equals('(')) {
  98366. ++$count;
  98367. } elseif ($tokens[$i]->equals(')')) {
  98368. --$count;
  98369. }
  98370. }
  98371. return 0 === $count;
  98372. }
  98373. public static function collect(Tokens $tokens, int $index): array
  98374. {
  98375. if (!$tokens[$index]->isGivenKind(T_ATTRIBUTE)) {
  98376. throw new \InvalidArgumentException('Given index must point to an attribute.');
  98377. }
  98378. while ($tokens[$prevIndex = $tokens->getPrevMeaningfulToken($index)]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  98379. $index = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $prevIndex);
  98380. }
  98381. $elements = [];
  98382. $openingIndex = $index;
  98383. do {
  98384. $elements[] = $element = self::collectOne($tokens, $openingIndex);
  98385. $openingIndex = $tokens->getNextMeaningfulToken($element->getEndIndex());
  98386. } while ($tokens[$openingIndex]->isGivenKind(T_ATTRIBUTE));
  98387. return $elements;
  98388. }
  98389. public static function collectOne(Tokens $tokens, int $index): AttributeAnalysis
  98390. {
  98391. if (!$tokens[$index]->isGivenKind(T_ATTRIBUTE)) {
  98392. throw new \InvalidArgumentException('Given index must point to an attribute.');
  98393. }
  98394. $startIndex = $index;
  98395. $prevIndex = $tokens->getPrevMeaningfulToken($index);
  98396. if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
  98397. $startIndex = $tokens->getNextNonWhitespace($prevIndex);
  98398. }
  98399. $closingIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $index);
  98400. $endIndex = $tokens->getNextNonWhitespace($closingIndex);
  98401. return new AttributeAnalysis(
  98402. $startIndex,
  98403. $endIndex - 1,
  98404. $index,
  98405. $closingIndex,
  98406. self::collectAttributes($tokens, $index, $closingIndex),
  98407. );
  98408. }
  98409. public static function determineAttributeFullyQualifiedName(Tokens $tokens, string $name, int $index): string
  98410. {
  98411. if ('\\' === $name[0]) {
  98412. return $name;
  98413. }
  98414. if (!$tokens[$index]->isGivenKind([T_STRING, T_NS_SEPARATOR])) {
  98415. $index = $tokens->getNextTokenOfKind($index, [[T_STRING], [T_NS_SEPARATOR]]);
  98416. }
  98417. [$namespaceAnalysis, $namespaceUseAnalyses] = NamespacesAnalyzer::collectNamespaceAnalysis($tokens, $index);
  98418. $namespace = $namespaceAnalysis->getFullName();
  98419. $firstTokenOfName = $tokens[$index]->getContent();
  98420. $namespaceUseAnalysis = $namespaceUseAnalyses[$firstTokenOfName] ?? false;
  98421. if ($namespaceUseAnalysis instanceof NamespaceUseAnalysis) {
  98422. $namespace = $namespaceUseAnalysis->getFullName();
  98423. if ($name === $firstTokenOfName) {
  98424. return $namespace;
  98425. }
  98426. $name = substr((string) strstr($name, '\\'), 1);
  98427. }
  98428. return $namespace.'\\'.$name;
  98429. }
  98430. private static function collectAttributes(Tokens $tokens, int $index, int $closingIndex): array
  98431. {
  98432. $elements = [];
  98433. do {
  98434. $attributeStartIndex = $index + 1;
  98435. $nameStartIndex = $tokens->getNextTokenOfKind($index, [[T_STRING], [T_NS_SEPARATOR]]);
  98436. $index = $tokens->getNextTokenOfKind($attributeStartIndex, ['(', ',', [CT::T_ATTRIBUTE_CLOSE]]);
  98437. $attributeName = $tokens->generatePartialCode($nameStartIndex, $tokens->getPrevMeaningfulToken($index));
  98438. if ($tokens[$index]->equals('(')) {
  98439. $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
  98440. $index = $tokens->getNextTokenOfKind($index, [',', [CT::T_ATTRIBUTE_CLOSE]]);
  98441. }
  98442. $elements[] = [
  98443. 'start' => $attributeStartIndex,
  98444. 'end' => $index - 1,
  98445. 'name' => $attributeName,
  98446. ];
  98447. $nextIndex = $index;
  98448. if ($nextIndex < $closingIndex) {
  98449. $nextIndex = $tokens->getNextMeaningfulToken($index);
  98450. }
  98451. } while ($nextIndex < $closingIndex);
  98452. --$index;
  98453. while ($tokens[$index]->isWhitespace()) {
  98454. if (Preg::match('/\R/', $tokens[$index]->getContent())) {
  98455. $lastElementKey = array_key_last($elements);
  98456. $elements[$lastElementKey]['end'] = $index - 1;
  98457. break;
  98458. }
  98459. --$index;
  98460. }
  98461. \assert(array_is_list($elements));
  98462. return $elements;
  98463. }
  98464. }
  98465. <?php
  98466. declare(strict_types=1);
  98467. namespace PhpCsFixer\Tokenizer;
  98468. final class CT
  98469. {
  98470. public const T_ARRAY_INDEX_CURLY_BRACE_CLOSE = 10_001;
  98471. public const T_ARRAY_INDEX_CURLY_BRACE_OPEN = 10_002;
  98472. public const T_ARRAY_SQUARE_BRACE_CLOSE = 10_003;
  98473. public const T_ARRAY_SQUARE_BRACE_OPEN = 10_004;
  98474. public const T_ARRAY_TYPEHINT = 10_005;
  98475. public const T_BRACE_CLASS_INSTANTIATION_CLOSE = 10_006;
  98476. public const T_BRACE_CLASS_INSTANTIATION_OPEN = 10_007;
  98477. public const T_CLASS_CONSTANT = 10_008;
  98478. public const T_CONST_IMPORT = 10_009;
  98479. public const T_CURLY_CLOSE = 10_010;
  98480. public const T_DESTRUCTURING_SQUARE_BRACE_CLOSE = 10_011;
  98481. public const T_DESTRUCTURING_SQUARE_BRACE_OPEN = 10_012;
  98482. public const T_DOLLAR_CLOSE_CURLY_BRACES = 10_013;
  98483. public const T_DYNAMIC_PROP_BRACE_CLOSE = 10_014;
  98484. public const T_DYNAMIC_PROP_BRACE_OPEN = 10_015;
  98485. public const T_DYNAMIC_VAR_BRACE_CLOSE = 10_016;
  98486. public const T_DYNAMIC_VAR_BRACE_OPEN = 10_017;
  98487. public const T_FUNCTION_IMPORT = 10_018;
  98488. public const T_GROUP_IMPORT_BRACE_CLOSE = 10_019;
  98489. public const T_GROUP_IMPORT_BRACE_OPEN = 10_020;
  98490. public const T_NAMESPACE_OPERATOR = 10_021;
  98491. public const T_NULLABLE_TYPE = 10_022;
  98492. public const T_RETURN_REF = 10_023;
  98493. public const T_TYPE_ALTERNATION = 10_024;
  98494. public const T_TYPE_COLON = 10_025;
  98495. public const T_USE_LAMBDA = 10_026;
  98496. public const T_USE_TRAIT = 10_027;
  98497. public const T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC = 10_028;
  98498. public const T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED = 10_029;
  98499. public const T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE = 10_030;
  98500. public const T_ATTRIBUTE_CLOSE = 10_031;
  98501. public const T_NAMED_ARGUMENT_NAME = 10_032;
  98502. public const T_NAMED_ARGUMENT_COLON = 10_033;
  98503. public const T_FIRST_CLASS_CALLABLE = 10_034;
  98504. public const T_TYPE_INTERSECTION = 10_035;
  98505. public const T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN = 10_036;
  98506. public const T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE = 10_037;
  98507. public const T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN = 10_038;
  98508. public const T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE = 10_039;
  98509. public const T_PROPERTY_HOOK_BRACE_OPEN = 10_040;
  98510. public const T_PROPERTY_HOOK_BRACE_CLOSE = 10_041;
  98511. private function __construct() {}
  98512. public static function getName(int $value): string
  98513. {
  98514. if (!self::has($value)) {
  98515. throw new \InvalidArgumentException(\sprintf('No custom token was found for "%s".', $value));
  98516. }
  98517. $tokens = self::getMapById();
  98518. \assert(isset($tokens[$value]));
  98519. return 'CT::'.$tokens[$value];
  98520. }
  98521. public static function has(int $value): bool
  98522. {
  98523. $tokens = self::getMapById();
  98524. return isset($tokens[$value]);
  98525. }
  98526. private static function getMapById(): array
  98527. {
  98528. static $constants;
  98529. if (null === $constants) {
  98530. $reflection = new \ReflectionClass(self::class);
  98531. $constants = array_flip($reflection->getConstants());
  98532. }
  98533. return $constants;
  98534. }
  98535. }
  98536. <?php
  98537. declare(strict_types=1);
  98538. namespace PhpCsFixer;
  98539. use PhpCsFixer\Doctrine\Annotation\Tokens as DoctrineAnnotationTokens;
  98540. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  98541. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  98542. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  98543. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  98544. use PhpCsFixer\Tokenizer\CT;
  98545. use PhpCsFixer\Tokenizer\FCT;
  98546. use PhpCsFixer\Tokenizer\Token;
  98547. use PhpCsFixer\Tokenizer\Tokens;
  98548. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  98549. /**
  98550. @phpstan-type
  98551. @phpstan-type
  98552. @implements
  98553. */
  98554. abstract class AbstractDoctrineAnnotationFixer extends AbstractFixer implements ConfigurableFixerInterface
  98555. {
  98556. private const CLASS_MODIFIERS = [T_ABSTRACT, T_FINAL, FCT::T_READONLY];
  98557. private const MODIFIER_KINDS = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_NS_SEPARATOR, T_STRING, CT::T_NULLABLE_TYPE, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET];
  98558. private array $classyElements;
  98559. public function isCandidate(Tokens $tokens): bool
  98560. {
  98561. return $tokens->isTokenKindFound(T_DOC_COMMENT);
  98562. }
  98563. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  98564. {
  98565. $analyzer = new TokensAnalyzer($tokens);
  98566. $this->classyElements = $analyzer->getClassyElements();
  98567. foreach ($tokens->findGivenKind(T_DOC_COMMENT) as $index => $docCommentToken) {
  98568. if (!$this->nextElementAcceptsDoctrineAnnotations($tokens, $index)) {
  98569. continue;
  98570. }
  98571. $doctrineAnnotationTokens = DoctrineAnnotationTokens::createFromDocComment(
  98572. $docCommentToken,
  98573. $this->configuration['ignored_tags']
  98574. );
  98575. $this->fixAnnotations($doctrineAnnotationTokens);
  98576. $tokens[$index] = new Token([T_DOC_COMMENT, $doctrineAnnotationTokens->getCode()]);
  98577. }
  98578. }
  98579. abstract protected function fixAnnotations(DoctrineAnnotationTokens $doctrineAnnotationTokens): void;
  98580. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  98581. {
  98582. return new FixerConfigurationResolver([
  98583. (new FixerOptionBuilder('ignored_tags', 'List of tags that must not be treated as Doctrine Annotations.'))
  98584. ->setAllowedTypes(['string[]'])
  98585. ->setDefault([
  98586. 'abstract',
  98587. 'access',
  98588. 'code',
  98589. 'deprec',
  98590. 'encode',
  98591. 'exception',
  98592. 'final',
  98593. 'ingroup',
  98594. 'inheritdoc',
  98595. 'inheritDoc',
  98596. 'magic',
  98597. 'name',
  98598. 'toc',
  98599. 'tutorial',
  98600. 'private',
  98601. 'static',
  98602. 'staticvar',
  98603. 'staticVar',
  98604. 'throw',
  98605. 'api',
  98606. 'author',
  98607. 'category',
  98608. 'copyright',
  98609. 'deprecated',
  98610. 'example',
  98611. 'filesource',
  98612. 'global',
  98613. 'ignore',
  98614. 'internal',
  98615. 'license',
  98616. 'link',
  98617. 'method',
  98618. 'package',
  98619. 'param',
  98620. 'property',
  98621. 'property-read',
  98622. 'property-write',
  98623. 'return',
  98624. 'see',
  98625. 'since',
  98626. 'source',
  98627. 'subpackage',
  98628. 'throws',
  98629. 'todo',
  98630. 'TODO',
  98631. 'usedBy',
  98632. 'uses',
  98633. 'var',
  98634. 'version',
  98635. 'after',
  98636. 'afterClass',
  98637. 'backupGlobals',
  98638. 'backupStaticAttributes',
  98639. 'before',
  98640. 'beforeClass',
  98641. 'codeCoverageIgnore',
  98642. 'codeCoverageIgnoreStart',
  98643. 'codeCoverageIgnoreEnd',
  98644. 'covers',
  98645. 'coversDefaultClass',
  98646. 'coversNothing',
  98647. 'dataProvider',
  98648. 'depends',
  98649. 'expectedException',
  98650. 'expectedExceptionCode',
  98651. 'expectedExceptionMessage',
  98652. 'expectedExceptionMessageRegExp',
  98653. 'group',
  98654. 'large',
  98655. 'medium',
  98656. 'preserveGlobalState',
  98657. 'requires',
  98658. 'runTestsInSeparateProcesses',
  98659. 'runInSeparateProcess',
  98660. 'small',
  98661. 'test',
  98662. 'testdox',
  98663. 'ticket',
  98664. 'uses',
  98665. 'SuppressWarnings',
  98666. 'noinspection',
  98667. 'package_version',
  98668. 'enduml',
  98669. 'startuml',
  98670. 'psalm',
  98671. 'phpstan',
  98672. 'template',
  98673. 'fix',
  98674. 'FIXME',
  98675. 'fixme',
  98676. 'override',
  98677. ])
  98678. ->getOption(),
  98679. ]);
  98680. }
  98681. private function nextElementAcceptsDoctrineAnnotations(Tokens $tokens, int $index): bool
  98682. {
  98683. do {
  98684. $index = $tokens->getNextMeaningfulToken($index);
  98685. if (null === $index) {
  98686. return false;
  98687. }
  98688. } while ($tokens[$index]->isGivenKind(self::CLASS_MODIFIERS));
  98689. if ($tokens[$index]->isGivenKind(T_CLASS)) {
  98690. return true;
  98691. }
  98692. while ($tokens[$index]->isGivenKind(self::MODIFIER_KINDS)) {
  98693. $index = $tokens->getNextMeaningfulToken($index);
  98694. }
  98695. if (!isset($this->classyElements[$index])) {
  98696. return false;
  98697. }
  98698. return $tokens[$this->classyElements[$index]['classIndex']]->isGivenKind(T_CLASS);
  98699. }
  98700. }
  98701. <?php
  98702. declare(strict_types=1);
  98703. namespace PhpCsFixer\Runner\Parallel;
  98704. /**
  98705. @readonly
  98706. */
  98707. final class ParallelConfig
  98708. {
  98709. public const DEFAULT_FILES_PER_PROCESS = 10;
  98710. public const DEFAULT_PROCESS_TIMEOUT = 120;
  98711. private int $filesPerProcess;
  98712. private int $maxProcesses;
  98713. private int $processTimeout;
  98714. public function __construct(
  98715. int $maxProcesses = 2,
  98716. int $filesPerProcess = self::DEFAULT_FILES_PER_PROCESS,
  98717. int $processTimeout = self::DEFAULT_PROCESS_TIMEOUT
  98718. ) {
  98719. if ($maxProcesses <= 0 || $filesPerProcess <= 0 || $processTimeout <= 0) {
  98720. throw new \InvalidArgumentException('Invalid parallelisation configuration: only positive integers are allowed');
  98721. }
  98722. $this->maxProcesses = $maxProcesses;
  98723. $this->filesPerProcess = $filesPerProcess;
  98724. $this->processTimeout = $processTimeout;
  98725. }
  98726. public function getFilesPerProcess(): int
  98727. {
  98728. return $this->filesPerProcess;
  98729. }
  98730. public function getMaxProcesses(): int
  98731. {
  98732. return $this->maxProcesses;
  98733. }
  98734. public function getProcessTimeout(): int
  98735. {
  98736. return $this->processTimeout;
  98737. }
  98738. }
  98739. <?php
  98740. declare(strict_types=1);
  98741. namespace PhpCsFixer\Runner\Parallel;
  98742. /**
  98743. @readonly
  98744. */
  98745. final class ProcessIdentifier
  98746. {
  98747. private const IDENTIFIER_PREFIX = 'php-cs-fixer_parallel_';
  98748. private string $identifier;
  98749. private function __construct(string $identifier)
  98750. {
  98751. $this->identifier = $identifier;
  98752. }
  98753. public function toString(): string
  98754. {
  98755. return $this->identifier;
  98756. }
  98757. public static function create(): self
  98758. {
  98759. return new self(uniqid(self::IDENTIFIER_PREFIX, true));
  98760. }
  98761. public static function fromRaw(string $identifier): self
  98762. {
  98763. if (!str_starts_with($identifier, self::IDENTIFIER_PREFIX)) {
  98764. throw new ParallelisationException(\sprintf('Invalid process identifier "%s".', $identifier));
  98765. }
  98766. return new self($identifier);
  98767. }
  98768. }
  98769. <?php
  98770. declare(strict_types=1);
  98771. namespace PhpCsFixer\Runner\Parallel;
  98772. use PhpCsFixer\Runner\RunnerConfig;
  98773. use React\EventLoop\LoopInterface;
  98774. use Symfony\Component\Console\Input\InputInterface;
  98775. use Symfony\Component\Process\PhpExecutableFinder;
  98776. /**
  98777. @readonly
  98778. */
  98779. final class ProcessFactory
  98780. {
  98781. private InputInterface $input;
  98782. public function __construct(InputInterface $input)
  98783. {
  98784. $this->input = $input;
  98785. }
  98786. public function create(
  98787. LoopInterface $loop,
  98788. RunnerConfig $runnerConfig,
  98789. ProcessIdentifier $identifier,
  98790. int $serverPort
  98791. ): Process {
  98792. $commandArgs = $this->getCommandArgs($serverPort, $identifier, $runnerConfig);
  98793. return new Process(
  98794. implode(' ', $commandArgs),
  98795. $loop,
  98796. $runnerConfig->getParallelConfig()->getProcessTimeout()
  98797. );
  98798. }
  98799. public function getCommandArgs(int $serverPort, ProcessIdentifier $identifier, RunnerConfig $runnerConfig): array
  98800. {
  98801. $phpBinary = (new PhpExecutableFinder())->find(false);
  98802. if (false === $phpBinary) {
  98803. throw new ParallelisationException('Cannot find PHP executable.');
  98804. }
  98805. $mainScript = realpath(__DIR__.'/../../../php-cs-fixer');
  98806. if (false === $mainScript
  98807. && isset($_SERVER['argv'][0])
  98808. && str_contains($_SERVER['argv'][0], 'php-cs-fixer')
  98809. ) {
  98810. $mainScript = $_SERVER['argv'][0];
  98811. }
  98812. if (!is_file($mainScript)) {
  98813. throw new ParallelisationException('Cannot determine Fixer executable.');
  98814. }
  98815. $commandArgs = [
  98816. escapeshellarg($phpBinary),
  98817. escapeshellarg($mainScript),
  98818. 'worker',
  98819. '--port',
  98820. (string) $serverPort,
  98821. '--identifier',
  98822. escapeshellarg($identifier->toString()),
  98823. ];
  98824. if ($runnerConfig->isDryRun()) {
  98825. $commandArgs[] = '--dry-run';
  98826. }
  98827. if (filter_var($this->input->getOption('diff'), FILTER_VALIDATE_BOOLEAN)) {
  98828. $commandArgs[] = '--diff';
  98829. }
  98830. if (filter_var($this->input->getOption('stop-on-violation'), FILTER_VALIDATE_BOOLEAN)) {
  98831. $commandArgs[] = '--stop-on-violation';
  98832. }
  98833. foreach (['allow-risky', 'config', 'rules', 'using-cache', 'cache-file'] as $option) {
  98834. $optionValue = $this->input->getOption($option);
  98835. if (null !== $optionValue) {
  98836. $commandArgs[] = "--{$option}";
  98837. $commandArgs[] = escapeshellarg($optionValue);
  98838. }
  98839. }
  98840. return $commandArgs;
  98841. }
  98842. }
  98843. <?php
  98844. declare(strict_types=1);
  98845. namespace PhpCsFixer\Runner\Parallel;
  98846. final class ParallelAction
  98847. {
  98848. public const RUNNER_REQUEST_ANALYSIS = 'requestAnalysis';
  98849. public const RUNNER_THANK_YOU = 'thankYou';
  98850. public const WORKER_ERROR_REPORT = 'errorReport';
  98851. public const WORKER_GET_FILE_CHUNK = 'getFileChunk';
  98852. public const WORKER_HELLO = 'hello';
  98853. public const WORKER_RESULT = 'result';
  98854. private function __construct() {}
  98855. }
  98856. <?php
  98857. declare(strict_types=1);
  98858. namespace PhpCsFixer\Runner\Parallel;
  98859. use Throwable;
  98860. final class WorkerException extends \RuntimeException
  98861. {
  98862. private string $originalTraceAsString;
  98863. private function __construct(string $message, int $code)
  98864. {
  98865. parent::__construct($message, $code);
  98866. }
  98867. public static function fromRaw(array $data): self
  98868. {
  98869. $exception = new self(
  98870. \sprintf('[%s] %s', $data['class'], $data['message']),
  98871. $data['code']
  98872. );
  98873. $exception->file = $data['file'];
  98874. $exception->line = $data['line'];
  98875. $exception->originalTraceAsString = \sprintf(
  98876. '## %s(%d)%s%s',
  98877. $data['file'],
  98878. $data['line'],
  98879. PHP_EOL,
  98880. $data['trace']
  98881. );
  98882. return $exception;
  98883. }
  98884. public function getOriginalTraceAsString(): string
  98885. {
  98886. return $this->originalTraceAsString;
  98887. }
  98888. }
  98889. <?php
  98890. declare(strict_types=1);
  98891. namespace PhpCsFixer\Runner\Parallel;
  98892. use Fidry\CpuCoreCounter\CpuCoreCounter;
  98893. use Fidry\CpuCoreCounter\Finder\DummyCpuCoreFinder;
  98894. use Fidry\CpuCoreCounter\Finder\FinderRegistry;
  98895. final class ParallelConfigFactory
  98896. {
  98897. private static ?CpuCoreCounter $cpuDetector = null;
  98898. private function __construct() {}
  98899. public static function sequential(): ParallelConfig
  98900. {
  98901. return new ParallelConfig(1);
  98902. }
  98903. public static function detect(
  98904. ?int $filesPerProcess = null,
  98905. ?int $processTimeout = null,
  98906. ?int $maxProcesses = null
  98907. ): ParallelConfig {
  98908. if (null === self::$cpuDetector) {
  98909. self::$cpuDetector = new CpuCoreCounter([
  98910. ...FinderRegistry::getDefaultLogicalFinders(),
  98911. new DummyCpuCoreFinder(1),
  98912. ]);
  98913. }
  98914. $available = self::$cpuDetector->getAvailableForParallelisation(1, $maxProcesses);
  98915. return new ParallelConfig(
  98916. $available->availableCpus,
  98917. $filesPerProcess ?? ParallelConfig::DEFAULT_FILES_PER_PROCESS,
  98918. $processTimeout ?? ParallelConfig::DEFAULT_PROCESS_TIMEOUT
  98919. );
  98920. }
  98921. }
  98922. <?php
  98923. declare(strict_types=1);
  98924. namespace PhpCsFixer\Runner\Parallel;
  98925. use React\Socket\ServerInterface;
  98926. final class ProcessPool
  98927. {
  98928. /**
  98929. @readonly
  98930. */
  98931. private ServerInterface $server;
  98932. /**
  98933. @readonly
  98934. */
  98935. private $onServerClose;
  98936. private array $processes = [];
  98937. public function __construct(ServerInterface $server, ?callable $onServerClose = null)
  98938. {
  98939. $this->server = $server;
  98940. $this->onServerClose = $onServerClose;
  98941. }
  98942. public function getProcess(ProcessIdentifier $identifier): Process
  98943. {
  98944. if (!isset($this->processes[$identifier->toString()])) {
  98945. throw ParallelisationException::forUnknownIdentifier($identifier);
  98946. }
  98947. return $this->processes[$identifier->toString()];
  98948. }
  98949. public function addProcess(ProcessIdentifier $identifier, Process $process): void
  98950. {
  98951. $this->processes[$identifier->toString()] = $process;
  98952. }
  98953. public function endProcessIfKnown(ProcessIdentifier $identifier): void
  98954. {
  98955. if (!isset($this->processes[$identifier->toString()])) {
  98956. return;
  98957. }
  98958. $this->endProcess($identifier);
  98959. }
  98960. public function endAll(): void
  98961. {
  98962. foreach ($this->processes as $identifier => $process) {
  98963. $this->endProcessIfKnown(ProcessIdentifier::fromRaw($identifier));
  98964. }
  98965. }
  98966. private function endProcess(ProcessIdentifier $identifier): void
  98967. {
  98968. $this->getProcess($identifier)->quit();
  98969. unset($this->processes[$identifier->toString()]);
  98970. if (0 === \count($this->processes)) {
  98971. $this->server->close();
  98972. if (null !== $this->onServerClose) {
  98973. ($this->onServerClose)();
  98974. }
  98975. }
  98976. }
  98977. }
  98978. <?php
  98979. declare(strict_types=1);
  98980. namespace PhpCsFixer\Runner\Parallel;
  98981. final class ParallelisationException extends \RuntimeException
  98982. {
  98983. public static function forUnknownIdentifier(ProcessIdentifier $identifier): self
  98984. {
  98985. return new self('Unknown process identifier: '.$identifier->toString());
  98986. }
  98987. }
  98988. <?php
  98989. declare(strict_types=1);
  98990. namespace PhpCsFixer\Runner\Parallel;
  98991. use React\ChildProcess\Process as ReactProcess;
  98992. use React\EventLoop\LoopInterface;
  98993. use React\EventLoop\TimerInterface;
  98994. use React\Stream\ReadableStreamInterface;
  98995. use React\Stream\WritableStreamInterface;
  98996. final class Process
  98997. {
  98998. private string $command;
  98999. private LoopInterface $loop;
  99000. private int $timeoutSeconds;
  99001. private ?ReactProcess $process = null;
  99002. private ?WritableStreamInterface $in = null;
  99003. private $stdErr;
  99004. private $stdOut;
  99005. private $onData;
  99006. private $onError;
  99007. private ?TimerInterface $timer = null;
  99008. public function __construct(string $command, LoopInterface $loop, int $timeoutSeconds)
  99009. {
  99010. $this->command = $command;
  99011. $this->loop = $loop;
  99012. $this->timeoutSeconds = $timeoutSeconds;
  99013. }
  99014. public function start(callable $onData, callable $onError, callable $onExit): void
  99015. {
  99016. $stdOut = tmpfile();
  99017. if (false === $stdOut) {
  99018. throw new ParallelisationException('Failed creating temp file for stdOut.');
  99019. }
  99020. $this->stdOut = $stdOut;
  99021. $stdErr = tmpfile();
  99022. if (false === $stdErr) {
  99023. throw new ParallelisationException('Failed creating temp file for stdErr.');
  99024. }
  99025. $this->stdErr = $stdErr;
  99026. $this->onData = $onData;
  99027. $this->onError = $onError;
  99028. $this->process = new ReactProcess($this->command, null, null, [
  99029. 1 => $this->stdOut,
  99030. 2 => $this->stdErr,
  99031. ]);
  99032. $this->process->start($this->loop);
  99033. $this->process->on('exit', function ($exitCode) use ($onExit): void {
  99034. $this->cancelTimer();
  99035. $output = '';
  99036. rewind($this->stdOut);
  99037. $stdOut = stream_get_contents($this->stdOut);
  99038. if (\is_string($stdOut)) {
  99039. $output .= $stdOut;
  99040. }
  99041. rewind($this->stdErr);
  99042. $stdErr = stream_get_contents($this->stdErr);
  99043. if (\is_string($stdErr)) {
  99044. $output .= $stdErr;
  99045. }
  99046. $onExit($exitCode, $output);
  99047. fclose($this->stdOut);
  99048. fclose($this->stdErr);
  99049. });
  99050. }
  99051. public function request(array $data): void
  99052. {
  99053. $this->cancelTimer();
  99054. if (null === $this->in) {
  99055. throw new ParallelisationException(
  99056. 'Process not connected with parallelisation operator, ensure `bindConnection()` was called'
  99057. );
  99058. }
  99059. $this->in->write($data);
  99060. $this->timer = $this->loop->addTimer($this->timeoutSeconds, function (): void {
  99061. ($this->onError)(
  99062. new \Exception(
  99063. \sprintf(
  99064. 'Child process timed out after %d seconds. Try making it longer using `ParallelConfig`.',
  99065. $this->timeoutSeconds
  99066. )
  99067. )
  99068. );
  99069. });
  99070. }
  99071. public function quit(): void
  99072. {
  99073. $this->cancelTimer();
  99074. if (null === $this->process || !$this->process->isRunning()) {
  99075. return;
  99076. }
  99077. foreach ($this->process->pipes as $pipe) {
  99078. $pipe->close();
  99079. }
  99080. if (null === $this->in) {
  99081. return;
  99082. }
  99083. $this->in->end();
  99084. }
  99085. public function bindConnection(ReadableStreamInterface $out, WritableStreamInterface $in): void
  99086. {
  99087. $this->in = $in;
  99088. $in->on('error', function (\Throwable $error): void {
  99089. ($this->onError)($error);
  99090. });
  99091. $out->on('data', function (array $json): void {
  99092. $this->cancelTimer();
  99093. ($this->onData)($json);
  99094. });
  99095. $out->on('error', function (\Throwable $error): void {
  99096. ($this->onError)($error);
  99097. });
  99098. }
  99099. private function cancelTimer(): void
  99100. {
  99101. if (null === $this->timer) {
  99102. return;
  99103. }
  99104. $this->loop->cancelTimer($this->timer);
  99105. $this->timer = null;
  99106. }
  99107. }
  99108. <?php
  99109. declare(strict_types=1);
  99110. namespace PhpCsFixer\Runner;
  99111. use PhpCsFixer\Linter\LintingResultInterface;
  99112. /**
  99113. @extends
  99114. */
  99115. interface LintingResultAwareFileIteratorInterface extends \Iterator
  99116. {
  99117. public function currentLintingResult(): ?LintingResultInterface;
  99118. }
  99119. <?php
  99120. declare(strict_types=1);
  99121. namespace PhpCsFixer\Runner;
  99122. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  99123. /**
  99124. @readonly
  99125. */
  99126. final class RunnerConfig
  99127. {
  99128. private bool $isDryRun;
  99129. private bool $stopOnViolation;
  99130. private ParallelConfig $parallelConfig;
  99131. private ?string $configFile;
  99132. public function __construct(
  99133. bool $isDryRun,
  99134. bool $stopOnViolation,
  99135. ParallelConfig $parallelConfig,
  99136. ?string $configFile = null
  99137. ) {
  99138. $this->isDryRun = $isDryRun;
  99139. $this->stopOnViolation = $stopOnViolation;
  99140. $this->parallelConfig = $parallelConfig;
  99141. $this->configFile = $configFile;
  99142. }
  99143. public function isDryRun(): bool
  99144. {
  99145. return $this->isDryRun;
  99146. }
  99147. public function shouldStopOnViolation(): bool
  99148. {
  99149. return $this->stopOnViolation;
  99150. }
  99151. public function getParallelConfig(): ParallelConfig
  99152. {
  99153. return $this->parallelConfig;
  99154. }
  99155. public function getConfigFile(): ?string
  99156. {
  99157. return $this->configFile;
  99158. }
  99159. }
  99160. <?php
  99161. declare(strict_types=1);
  99162. namespace PhpCsFixer\Runner;
  99163. use PhpCsFixer\Cache\CacheManagerInterface;
  99164. use PhpCsFixer\FileReader;
  99165. use PhpCsFixer\Runner\Event\FileProcessed;
  99166. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  99167. use Symfony\Contracts\EventDispatcher\Event;
  99168. /**
  99169. @extends
  99170. */
  99171. final class FileFilterIterator extends \FilterIterator
  99172. {
  99173. private ?EventDispatcherInterface $eventDispatcher;
  99174. private CacheManagerInterface $cacheManager;
  99175. private array $visitedElements = [];
  99176. public function __construct(
  99177. \Traversable $iterator,
  99178. ?EventDispatcherInterface $eventDispatcher,
  99179. CacheManagerInterface $cacheManager
  99180. ) {
  99181. if (!$iterator instanceof \Iterator) {
  99182. $iterator = new \IteratorIterator($iterator);
  99183. }
  99184. parent::__construct($iterator);
  99185. $this->eventDispatcher = $eventDispatcher;
  99186. $this->cacheManager = $cacheManager;
  99187. }
  99188. public function accept(): bool
  99189. {
  99190. $file = $this->current();
  99191. if (!$file instanceof \SplFileInfo) {
  99192. throw new \RuntimeException(
  99193. \sprintf(
  99194. 'Expected instance of "\SplFileInfo", got "%s".',
  99195. get_debug_type($file)
  99196. )
  99197. );
  99198. }
  99199. $path = $file->isLink() ? $file->getPathname() : $file->getRealPath();
  99200. if (isset($this->visitedElements[$path])) {
  99201. return false;
  99202. }
  99203. $this->visitedElements[$path] = true;
  99204. if (!$file->isFile() || $file->isLink()) {
  99205. return false;
  99206. }
  99207. $content = FileReader::createSingleton()->read($path);
  99208. if (
  99209. '' === $content
  99210. || !$this->cacheManager->needFixing($file->getPathname(), $content)
  99211. ) {
  99212. $this->dispatchEvent(FileProcessed::NAME, new FileProcessed(FileProcessed::STATUS_SKIPPED));
  99213. return false;
  99214. }
  99215. return true;
  99216. }
  99217. private function dispatchEvent(string $name, Event $event): void
  99218. {
  99219. if (null === $this->eventDispatcher) {
  99220. return;
  99221. }
  99222. $this->eventDispatcher->dispatch($event, $name);
  99223. }
  99224. }
  99225. <?php
  99226. declare(strict_types=1);
  99227. namespace PhpCsFixer\Runner;
  99228. use PhpCsFixer\Linter\LinterInterface;
  99229. use PhpCsFixer\Linter\LintingResultInterface;
  99230. /**
  99231. @extends
  99232. */
  99233. final class LintingFileIterator extends \IteratorIterator implements LintingResultAwareFileIteratorInterface
  99234. {
  99235. private ?LintingResultInterface $currentResult = null;
  99236. private LinterInterface $linter;
  99237. public function __construct(\Iterator $iterator, LinterInterface $linter)
  99238. {
  99239. parent::__construct($iterator);
  99240. $this->linter = $linter;
  99241. }
  99242. public function currentLintingResult(): ?LintingResultInterface
  99243. {
  99244. return $this->currentResult;
  99245. }
  99246. public function next(): void
  99247. {
  99248. parent::next();
  99249. $this->currentResult = $this->valid() ? $this->handleItem($this->current()) : null;
  99250. }
  99251. public function rewind(): void
  99252. {
  99253. parent::rewind();
  99254. $this->currentResult = $this->valid() ? $this->handleItem($this->current()) : null;
  99255. }
  99256. private function handleItem(\SplFileInfo $file): LintingResultInterface
  99257. {
  99258. return $this->linter->lintFile($file->getRealPath());
  99259. }
  99260. }
  99261. <?php
  99262. declare(strict_types=1);
  99263. namespace PhpCsFixer\Runner;
  99264. use PhpCsFixer\Linter\LinterInterface;
  99265. use PhpCsFixer\Linter\LintingResultInterface;
  99266. /**
  99267. @extends
  99268. */
  99269. final class FileCachingLintingFileIterator extends \CachingIterator implements LintingResultAwareFileIteratorInterface
  99270. {
  99271. private LinterInterface $linter;
  99272. private ?LintingResultInterface $currentResult = null;
  99273. private ?LintingResultInterface $nextResult = null;
  99274. public function __construct(\Iterator $iterator, LinterInterface $linter)
  99275. {
  99276. parent::__construct($iterator);
  99277. $this->linter = $linter;
  99278. }
  99279. public function currentLintingResult(): ?LintingResultInterface
  99280. {
  99281. return $this->currentResult;
  99282. }
  99283. public function next(): void
  99284. {
  99285. parent::next();
  99286. $this->currentResult = $this->nextResult;
  99287. if ($this->hasNext()) {
  99288. $this->nextResult = $this->handleItem($this->getInnerIterator()->current());
  99289. }
  99290. }
  99291. public function rewind(): void
  99292. {
  99293. parent::rewind();
  99294. if ($this->valid()) {
  99295. $this->currentResult = $this->handleItem($this->current());
  99296. }
  99297. if ($this->hasNext()) {
  99298. $this->nextResult = $this->handleItem($this->getInnerIterator()->current());
  99299. }
  99300. }
  99301. private function handleItem(\SplFileInfo $file): LintingResultInterface
  99302. {
  99303. return $this->linter->lintFile($file->getRealPath());
  99304. }
  99305. }
  99306. <?php
  99307. declare(strict_types=1);
  99308. namespace PhpCsFixer\Runner\Event;
  99309. use Symfony\Contracts\EventDispatcher\Event;
  99310. final class FileProcessed extends Event
  99311. {
  99312. public const NAME = 'fixer.file_processed';
  99313. public const STATUS_INVALID = 1;
  99314. public const STATUS_SKIPPED = 2;
  99315. public const STATUS_NO_CHANGES = 3;
  99316. public const STATUS_FIXED = 4;
  99317. public const STATUS_EXCEPTION = 5;
  99318. public const STATUS_LINT = 6;
  99319. private int $status;
  99320. private ?string $fileRelativePath;
  99321. private ?string $fileHash;
  99322. public function __construct(int $status, ?string $fileRelativePath = null, ?string $fileHash = null)
  99323. {
  99324. $this->status = $status;
  99325. $this->fileRelativePath = $fileRelativePath;
  99326. $this->fileHash = $fileHash;
  99327. }
  99328. public function getStatus(): int
  99329. {
  99330. return $this->status;
  99331. }
  99332. public function getFileRelativePath(): ?string
  99333. {
  99334. return $this->fileRelativePath;
  99335. }
  99336. public function getFileHash(): ?string
  99337. {
  99338. return $this->fileHash;
  99339. }
  99340. }
  99341. <?php
  99342. declare(strict_types=1);
  99343. namespace PhpCsFixer\Runner\Event;
  99344. use Symfony\Contracts\EventDispatcher\Event;
  99345. final class AnalysisStarted extends Event
  99346. {
  99347. public const NAME = 'fixer.analysis_started';
  99348. public const MODE_SEQUENTIAL = 'sequential';
  99349. public const MODE_PARALLEL = 'parallel';
  99350. private string $mode;
  99351. private bool $dryRun;
  99352. public function __construct(string $mode, bool $dryRun)
  99353. {
  99354. $this->mode = $mode;
  99355. $this->dryRun = $dryRun;
  99356. }
  99357. public function getMode(): string
  99358. {
  99359. return $this->mode;
  99360. }
  99361. public function isDryRun(): bool
  99362. {
  99363. return $this->dryRun;
  99364. }
  99365. }
  99366. <?php
  99367. declare(strict_types=1);
  99368. namespace PhpCsFixer\Runner;
  99369. use Clue\React\NDJson\Decoder;
  99370. use Clue\React\NDJson\Encoder;
  99371. use PhpCsFixer\AbstractFixer;
  99372. use PhpCsFixer\Cache\CacheManagerInterface;
  99373. use PhpCsFixer\Cache\Directory;
  99374. use PhpCsFixer\Cache\DirectoryInterface;
  99375. use PhpCsFixer\Console\Command\WorkerCommand;
  99376. use PhpCsFixer\Differ\DifferInterface;
  99377. use PhpCsFixer\Error\Error;
  99378. use PhpCsFixer\Error\ErrorsManager;
  99379. use PhpCsFixer\Error\SourceExceptionFactory;
  99380. use PhpCsFixer\FileReader;
  99381. use PhpCsFixer\Fixer\FixerInterface;
  99382. use PhpCsFixer\Linter\LinterInterface;
  99383. use PhpCsFixer\Linter\LintingException;
  99384. use PhpCsFixer\Linter\LintingResultInterface;
  99385. use PhpCsFixer\Preg;
  99386. use PhpCsFixer\Runner\Event\AnalysisStarted;
  99387. use PhpCsFixer\Runner\Event\FileProcessed;
  99388. use PhpCsFixer\Runner\Parallel\ParallelAction;
  99389. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  99390. use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
  99391. use PhpCsFixer\Runner\Parallel\ParallelisationException;
  99392. use PhpCsFixer\Runner\Parallel\ProcessFactory;
  99393. use PhpCsFixer\Runner\Parallel\ProcessIdentifier;
  99394. use PhpCsFixer\Runner\Parallel\ProcessPool;
  99395. use PhpCsFixer\Runner\Parallel\WorkerException;
  99396. use PhpCsFixer\Tokenizer\Tokens;
  99397. use React\EventLoop\StreamSelectLoop;
  99398. use React\Socket\ConnectionInterface;
  99399. use React\Socket\TcpServer;
  99400. use Symfony\Component\Console\Input\InputInterface;
  99401. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  99402. use Symfony\Component\Filesystem\Exception\IOException;
  99403. use Symfony\Contracts\EventDispatcher\Event;
  99404. /**
  99405. @phpstan-type
  99406. */
  99407. final class Runner
  99408. {
  99409. private const PARALLEL_BUFFER_SIZE = 16 * (1_024 * 1_024 );
  99410. private DifferInterface $differ;
  99411. private DirectoryInterface $directory;
  99412. private ?EventDispatcherInterface $eventDispatcher;
  99413. private ErrorsManager $errorsManager;
  99414. private CacheManagerInterface $cacheManager;
  99415. private bool $isDryRun;
  99416. private LinterInterface $linter;
  99417. private ?\Traversable $fileIterator = null;
  99418. private int $fileCount;
  99419. private array $fixers;
  99420. private bool $stopOnViolation;
  99421. private ParallelConfig $parallelConfig;
  99422. private ?InputInterface $input;
  99423. private ?string $configFile;
  99424. public function __construct(
  99425. ?\Traversable $fileIterator,
  99426. array $fixers,
  99427. DifferInterface $differ,
  99428. ?EventDispatcherInterface $eventDispatcher,
  99429. ErrorsManager $errorsManager,
  99430. LinterInterface $linter,
  99431. bool $isDryRun,
  99432. CacheManagerInterface $cacheManager,
  99433. ?DirectoryInterface $directory = null,
  99434. bool $stopOnViolation = false,
  99435. ?ParallelConfig $parallelConfig = null,
  99436. ?InputInterface $input = null,
  99437. ?string $configFile = null
  99438. ) {
  99439. $this->fileCount = null !== $fileIterator ? \count(iterator_to_array($fileIterator)) : 0;
  99440. $this->fileIterator = $fileIterator;
  99441. $this->fixers = $fixers;
  99442. $this->differ = $differ;
  99443. $this->eventDispatcher = $eventDispatcher;
  99444. $this->errorsManager = $errorsManager;
  99445. $this->linter = $linter;
  99446. $this->isDryRun = $isDryRun;
  99447. $this->cacheManager = $cacheManager;
  99448. $this->directory = $directory ?? new Directory('');
  99449. $this->stopOnViolation = $stopOnViolation;
  99450. $this->parallelConfig = $parallelConfig ?? ParallelConfigFactory::sequential();
  99451. $this->input = $input;
  99452. $this->configFile = $configFile;
  99453. }
  99454. public function setFileIterator(iterable $fileIterator): void
  99455. {
  99456. $this->fileIterator = $fileIterator;
  99457. $this->fileCount = \count(iterator_to_array($fileIterator));
  99458. }
  99459. public function fix(): array
  99460. {
  99461. if (0 === $this->fileCount) {
  99462. return [];
  99463. }
  99464. if (null === $this->input) {
  99465. return $this->fixSequential();
  99466. }
  99467. if (
  99468. 1 === $this->parallelConfig->getMaxProcesses()
  99469. || $this->fileCount <= $this->parallelConfig->getFilesPerProcess()
  99470. ) {
  99471. return $this->fixSequential();
  99472. }
  99473. return $this->fixParallel();
  99474. }
  99475. private function fixParallel(): array
  99476. {
  99477. $this->dispatchEvent(AnalysisStarted::NAME, new AnalysisStarted(AnalysisStarted::MODE_PARALLEL, $this->isDryRun));
  99478. $changed = [];
  99479. $streamSelectLoop = new StreamSelectLoop();
  99480. $server = new TcpServer('127.0.0.1:0', $streamSelectLoop);
  99481. $serverPort = parse_url($server->getAddress() ?? '', PHP_URL_PORT);
  99482. if (!is_numeric($serverPort)) {
  99483. throw new ParallelisationException(\sprintf(
  99484. 'Unable to parse server port from "%s"',
  99485. $server->getAddress() ?? ''
  99486. ));
  99487. }
  99488. $processPool = new ProcessPool($server);
  99489. $maxFilesPerProcess = $this->parallelConfig->getFilesPerProcess();
  99490. $fileIterator = $this->getFilteringFileIterator();
  99491. $fileIterator->rewind();
  99492. $getFileChunk = static function () use ($fileIterator, $maxFilesPerProcess): array {
  99493. $files = [];
  99494. while (\count($files) < $maxFilesPerProcess) {
  99495. $current = $fileIterator->current();
  99496. if (null === $current) {
  99497. break;
  99498. }
  99499. $files[] = $current->getPathname();
  99500. $fileIterator->next();
  99501. }
  99502. return $files;
  99503. };
  99504. $server->on('connection', static function (ConnectionInterface $connection) use ($processPool, $getFileChunk): void {
  99505. $decoder = new Decoder(
  99506. $connection,
  99507. true,
  99508. 512,
  99509. JSON_INVALID_UTF8_IGNORE,
  99510. self::PARALLEL_BUFFER_SIZE
  99511. );
  99512. $encoder = new Encoder($connection, JSON_INVALID_UTF8_IGNORE);
  99513. $decoder->on('data', static function (array $data) use ($processPool, $getFileChunk, $decoder, $encoder): void {
  99514. if (ParallelAction::WORKER_HELLO !== $data['action']) {
  99515. return;
  99516. }
  99517. $identifier = ProcessIdentifier::fromRaw($data['identifier']);
  99518. $process = $processPool->getProcess($identifier);
  99519. $process->bindConnection($decoder, $encoder);
  99520. $fileChunk = $getFileChunk();
  99521. if (0 === \count($fileChunk)) {
  99522. $process->request(['action' => ParallelAction::RUNNER_THANK_YOU]);
  99523. $processPool->endProcessIfKnown($identifier);
  99524. return;
  99525. }
  99526. $process->request(['action' => ParallelAction::RUNNER_REQUEST_ANALYSIS, 'files' => $fileChunk]);
  99527. });
  99528. });
  99529. $processesToSpawn = min(
  99530. $this->parallelConfig->getMaxProcesses(),
  99531. max(
  99532. 1,
  99533. (int) ceil($this->fileCount / $this->parallelConfig->getFilesPerProcess()),
  99534. )
  99535. );
  99536. $processFactory = new ProcessFactory($this->input);
  99537. for ($i = 0; $i < $processesToSpawn; ++$i) {
  99538. $identifier = ProcessIdentifier::create();
  99539. $process = $processFactory->create(
  99540. $streamSelectLoop,
  99541. new RunnerConfig(
  99542. $this->isDryRun,
  99543. $this->stopOnViolation,
  99544. $this->parallelConfig,
  99545. $this->configFile
  99546. ),
  99547. $identifier,
  99548. $serverPort,
  99549. );
  99550. $processPool->addProcess($identifier, $process);
  99551. $process->start(
  99552. function (array $workerResponse) use ($processPool, $process, $identifier, $getFileChunk, &$changed): void {
  99553. if (ParallelAction::WORKER_RESULT === $workerResponse['action']) {
  99554. $this->dispatchEvent(FileProcessed::NAME, new FileProcessed($workerResponse['status']));
  99555. if (isset($workerResponse['fileHash'])) {
  99556. $this->cacheManager->setFileHash($workerResponse['file'], $workerResponse['fileHash']);
  99557. }
  99558. foreach ($workerResponse['errors'] ?? [] as $error) {
  99559. $this->errorsManager->report(new Error(
  99560. $error['type'],
  99561. $error['filePath'],
  99562. null !== $error['source']
  99563. ? SourceExceptionFactory::fromArray($error['source'])
  99564. : null,
  99565. $error['appliedFixers'],
  99566. $error['diff']
  99567. ));
  99568. }
  99569. if (isset($workerResponse['fixInfo'])) {
  99570. $relativePath = $this->directory->getRelativePathTo($workerResponse['file']);
  99571. $changed[$relativePath] = $workerResponse['fixInfo'];
  99572. if ($this->stopOnViolation) {
  99573. $processPool->endAll();
  99574. return;
  99575. }
  99576. }
  99577. return;
  99578. }
  99579. if (ParallelAction::WORKER_GET_FILE_CHUNK === $workerResponse['action']) {
  99580. $fileChunk = $getFileChunk();
  99581. if (0 === \count($fileChunk)) {
  99582. $process->request(['action' => ParallelAction::RUNNER_THANK_YOU]);
  99583. $processPool->endProcessIfKnown($identifier);
  99584. return;
  99585. }
  99586. $process->request(['action' => ParallelAction::RUNNER_REQUEST_ANALYSIS, 'files' => $fileChunk]);
  99587. return;
  99588. }
  99589. if (ParallelAction::WORKER_ERROR_REPORT === $workerResponse['action']) {
  99590. throw WorkerException::fromRaw($workerResponse);
  99591. }
  99592. throw new ParallelisationException('Unsupported action: '.($workerResponse['action'] ?? 'n/a'));
  99593. },
  99594. static function (\Throwable $error) use ($processPool): void {
  99595. $processPool->endAll();
  99596. throw new ParallelisationException($error->getMessage(), $error->getCode(), $error);
  99597. },
  99598. static function ($exitCode, string $output) use ($processPool, $identifier): void {
  99599. $processPool->endProcessIfKnown($identifier);
  99600. if (0 === $exitCode || null === $exitCode) {
  99601. return;
  99602. }
  99603. $errorsReported = Preg::matchAll(
  99604. \sprintf('/^(?:%s)([^\n]+)+/m', WorkerCommand::ERROR_PREFIX),
  99605. $output,
  99606. $matches
  99607. );
  99608. if ($errorsReported > 0) {
  99609. throw WorkerException::fromRaw(json_decode($matches[1][0], true));
  99610. }
  99611. }
  99612. );
  99613. }
  99614. $streamSelectLoop->run();
  99615. return $changed;
  99616. }
  99617. private function fixSequential(): array
  99618. {
  99619. $this->dispatchEvent(AnalysisStarted::NAME, new AnalysisStarted(AnalysisStarted::MODE_SEQUENTIAL, $this->isDryRun));
  99620. $changed = [];
  99621. $collection = $this->getLintingFileIterator();
  99622. foreach ($collection as $file) {
  99623. $fixInfo = $this->fixFile($file, $collection->currentLintingResult());
  99624. Tokens::clearCache();
  99625. if (null !== $fixInfo) {
  99626. $relativePath = $this->directory->getRelativePathTo($file->__toString());
  99627. $changed[$relativePath] = $fixInfo;
  99628. if ($this->stopOnViolation) {
  99629. break;
  99630. }
  99631. }
  99632. }
  99633. return $changed;
  99634. }
  99635. private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult): ?array
  99636. {
  99637. $filePathname = $file->getPathname();
  99638. try {
  99639. $lintingResult->check();
  99640. } catch (LintingException $e) {
  99641. $this->dispatchEvent(
  99642. FileProcessed::NAME,
  99643. new FileProcessed(FileProcessed::STATUS_INVALID)
  99644. );
  99645. $this->errorsManager->report(new Error(Error::TYPE_INVALID, $filePathname, $e));
  99646. return null;
  99647. }
  99648. $old = FileReader::createSingleton()->read($file->getRealPath());
  99649. $tokens = Tokens::fromCode($old);
  99650. $oldHash = $tokens->getCodeHash();
  99651. $new = $old;
  99652. $newHash = $oldHash;
  99653. $appliedFixers = [];
  99654. try {
  99655. foreach ($this->fixers as $fixer) {
  99656. if (
  99657. !$fixer instanceof AbstractFixer
  99658. && (!$fixer->supports($file) || !$fixer->isCandidate($tokens))
  99659. ) {
  99660. continue;
  99661. }
  99662. $fixer->fix($file, $tokens);
  99663. if ($tokens->isChanged()) {
  99664. $tokens->clearEmptyTokens();
  99665. $tokens->clearChanged();
  99666. $appliedFixers[] = $fixer->getName();
  99667. }
  99668. }
  99669. } catch (\ParseError $e) {
  99670. $this->dispatchEvent(FileProcessed::NAME, new FileProcessed(FileProcessed::STATUS_LINT));
  99671. $this->errorsManager->report(new Error(Error::TYPE_LINT, $filePathname, $e));
  99672. return null;
  99673. } catch (\Throwable $e) {
  99674. $this->processException($filePathname, $e);
  99675. return null;
  99676. }
  99677. $fixInfo = null;
  99678. if ([] !== $appliedFixers) {
  99679. $new = $tokens->generateCode();
  99680. $newHash = $tokens->getCodeHash();
  99681. }
  99682. if ($oldHash !== $newHash) {
  99683. $fixInfo = [
  99684. 'appliedFixers' => $appliedFixers,
  99685. 'diff' => $this->differ->diff($old, $new, $file),
  99686. ];
  99687. try {
  99688. $this->linter->lintSource($new)->check();
  99689. } catch (LintingException $e) {
  99690. $this->dispatchEvent(FileProcessed::NAME, new FileProcessed(FileProcessed::STATUS_LINT));
  99691. $this->errorsManager->report(new Error(Error::TYPE_LINT, $filePathname, $e, $fixInfo['appliedFixers'], $fixInfo['diff']));
  99692. return null;
  99693. }
  99694. if (!$this->isDryRun) {
  99695. $fileRealPath = $file->getRealPath();
  99696. if (!file_exists($fileRealPath)) {
  99697. throw new IOException(
  99698. \sprintf('Failed to write file "%s" (no longer) exists.', $file->getPathname()),
  99699. 0,
  99700. null,
  99701. $file->getPathname()
  99702. );
  99703. }
  99704. if (is_dir($fileRealPath)) {
  99705. throw new IOException(
  99706. \sprintf('Cannot write file "%s" as the location exists as directory.', $fileRealPath),
  99707. 0,
  99708. null,
  99709. $fileRealPath
  99710. );
  99711. }
  99712. if (!is_writable($fileRealPath)) {
  99713. throw new IOException(
  99714. \sprintf('Cannot write to file "%s" as it is not writable.', $fileRealPath),
  99715. 0,
  99716. null,
  99717. $fileRealPath
  99718. );
  99719. }
  99720. if (false === @file_put_contents($fileRealPath, $new)) {
  99721. $error = error_get_last();
  99722. throw new IOException(
  99723. \sprintf('Failed to write file "%s", "%s".', $fileRealPath, null !== $error ? $error['message'] : 'no reason available'),
  99724. 0,
  99725. null,
  99726. $fileRealPath
  99727. );
  99728. }
  99729. }
  99730. }
  99731. $this->cacheManager->setFileHash($filePathname, $newHash);
  99732. $this->dispatchEvent(
  99733. FileProcessed::NAME,
  99734. new FileProcessed(null !== $fixInfo ? FileProcessed::STATUS_FIXED : FileProcessed::STATUS_NO_CHANGES, $filePathname, $newHash)
  99735. );
  99736. return $fixInfo;
  99737. }
  99738. private function processException(string $name, \Throwable $e): void
  99739. {
  99740. $this->dispatchEvent(FileProcessed::NAME, new FileProcessed(FileProcessed::STATUS_EXCEPTION));
  99741. $this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $name, $e));
  99742. }
  99743. private function dispatchEvent(string $name, Event $event): void
  99744. {
  99745. if (null === $this->eventDispatcher) {
  99746. return;
  99747. }
  99748. $this->eventDispatcher->dispatch($event, $name);
  99749. }
  99750. private function getLintingFileIterator(): LintingResultAwareFileIteratorInterface
  99751. {
  99752. $fileFilterIterator = $this->getFilteringFileIterator();
  99753. return $this->linter->isAsync()
  99754. ? new FileCachingLintingFileIterator($fileFilterIterator, $this->linter)
  99755. : new LintingFileIterator($fileFilterIterator, $this->linter);
  99756. }
  99757. private function getFilteringFileIterator(): FileFilterIterator
  99758. {
  99759. if (null === $this->fileIterator) {
  99760. throw new \RuntimeException('File iterator is not configured. Pass paths during Runner initialisation or set them after with `setFileIterator()`.');
  99761. }
  99762. return new FileFilterIterator(
  99763. $this->fileIterator instanceof \IteratorAggregate
  99764. ? $this->fileIterator->getIterator()
  99765. : $this->fileIterator,
  99766. $this->eventDispatcher,
  99767. $this->cacheManager
  99768. );
  99769. }
  99770. }
  99771. <?php
  99772. declare(strict_types=1);
  99773. namespace PhpCsFixer\FixerConfiguration;
  99774. /**
  99775. @readonly
  99776. */
  99777. final class AllowedValueSubset
  99778. {
  99779. private array $allowedValues;
  99780. public function __construct(array $allowedValues)
  99781. {
  99782. sort($allowedValues, SORT_FLAG_CASE | SORT_STRING);
  99783. $this->allowedValues = $allowedValues;
  99784. }
  99785. public function __invoke($values): bool
  99786. {
  99787. if (!\is_array($values)) {
  99788. return false;
  99789. }
  99790. foreach ($values as $value) {
  99791. if (!\in_array($value, $this->allowedValues, true)) {
  99792. return false;
  99793. }
  99794. }
  99795. return true;
  99796. }
  99797. public function getAllowedValues(): array
  99798. {
  99799. return $this->allowedValues;
  99800. }
  99801. }
  99802. <?php
  99803. declare(strict_types=1);
  99804. namespace PhpCsFixer\FixerConfiguration;
  99805. use PhpCsFixer\Preg;
  99806. use PhpCsFixer\Utils;
  99807. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  99808. use Symfony\Component\OptionsResolver\OptionsResolver;
  99809. /**
  99810. @readonly
  99811. */
  99812. final class FixerConfigurationResolver implements FixerConfigurationResolverInterface
  99813. {
  99814. /**
  99815. @readonly
  99816. */
  99817. private array $options;
  99818. public function __construct(iterable $options)
  99819. {
  99820. $fixerOptionSorter = new FixerOptionSorter();
  99821. $this->validateOptions($options);
  99822. $this->options = $fixerOptionSorter->sort($options);
  99823. if (0 === \count($this->options)) {
  99824. throw new \LogicException('Options cannot be empty.');
  99825. }
  99826. }
  99827. public function getOptions(): array
  99828. {
  99829. return $this->options;
  99830. }
  99831. public function resolve(array $configuration): array
  99832. {
  99833. $resolver = new OptionsResolver();
  99834. foreach ($this->options as $option) {
  99835. $name = $option->getName();
  99836. if ($option instanceof AliasedFixerOption) {
  99837. $alias = $option->getAlias();
  99838. if (\array_key_exists($alias, $configuration)) {
  99839. if (\array_key_exists($name, $configuration)) {
  99840. throw new InvalidOptionsException(\sprintf('Aliased option "%s"/"%s" is passed multiple times.', $name, $alias));
  99841. }
  99842. Utils::triggerDeprecation(new \RuntimeException(\sprintf(
  99843. 'Option "%s" is deprecated, use "%s" instead.',
  99844. $alias,
  99845. $name
  99846. )));
  99847. $configuration[$name] = $configuration[$alias];
  99848. unset($configuration[$alias]);
  99849. }
  99850. }
  99851. if ($option->hasDefault()) {
  99852. $resolver->setDefault($name, $option->getDefault());
  99853. } else {
  99854. $resolver->setRequired($name);
  99855. }
  99856. $allowedValues = $option->getAllowedValues();
  99857. if (null !== $allowedValues) {
  99858. foreach ($allowedValues as &$allowedValue) {
  99859. if (\is_object($allowedValue) && \is_callable($allowedValue)) {
  99860. $allowedValue = static fn ( $values) => $allowedValue($values);
  99861. }
  99862. }
  99863. $resolver->setAllowedValues($name, $allowedValues);
  99864. }
  99865. $allowedTypes = $option->getAllowedTypes();
  99866. if (null !== $allowedTypes) {
  99867. $allowedTypesNormalised = array_map(
  99868. static function (string $type): string {
  99869. $matches = [];
  99870. if (true === Preg::match('/array<\w+,\s*(\??[\w\'|]+)>/', $type, $matches)) {
  99871. if ('?' === $matches[1][0]) {
  99872. return 'array';
  99873. }
  99874. if ("'" === $matches[1][0]) {
  99875. return 'string[]';
  99876. }
  99877. return $matches[1].'[]';
  99878. }
  99879. return str_replace('class-string', 'string', $type);
  99880. },
  99881. $allowedTypes,
  99882. );
  99883. $resolver->setAllowedTypes($name, $allowedTypesNormalised);
  99884. }
  99885. $normalizer = $option->getNormalizer();
  99886. if (null !== $normalizer) {
  99887. $resolver->setNormalizer($name, $normalizer);
  99888. }
  99889. }
  99890. return $resolver->resolve($configuration);
  99891. }
  99892. private function validateOptions(iterable $options): void
  99893. {
  99894. $names = [];
  99895. foreach ($options as $option) {
  99896. $name = $option->getName();
  99897. if (\in_array($name, $names, true)) {
  99898. throw new \LogicException(\sprintf('The "%s" option is defined multiple times.', $name));
  99899. }
  99900. $names[] = $name;
  99901. }
  99902. }
  99903. }
  99904. <?php
  99905. declare(strict_types=1);
  99906. namespace PhpCsFixer\FixerConfiguration;
  99907. interface DeprecatedFixerOptionInterface extends FixerOptionInterface
  99908. {
  99909. public function getDeprecationMessage(): string;
  99910. }
  99911. <?php
  99912. declare(strict_types=1);
  99913. namespace PhpCsFixer\FixerConfiguration;
  99914. /**
  99915. @readonly
  99916. */
  99917. final class FixerOption implements FixerOptionInterface
  99918. {
  99919. private string $name;
  99920. private string $description;
  99921. private bool $isRequired;
  99922. private $default;
  99923. private ?array $allowedTypes;
  99924. private ?array $allowedValues;
  99925. private ?\Closure $normalizer;
  99926. public function __construct(
  99927. string $name,
  99928. string $description,
  99929. bool $isRequired = true,
  99930. $default = null,
  99931. ?array $allowedTypes = null,
  99932. ?array $allowedValues = null,
  99933. ?\Closure $normalizer = null
  99934. ) {
  99935. if ($isRequired && null !== $default) {
  99936. throw new \LogicException('Required options cannot have a default value.');
  99937. }
  99938. if (null !== $allowedValues) {
  99939. foreach ($allowedValues as &$allowedValue) {
  99940. if ($allowedValue instanceof \Closure) {
  99941. $allowedValue = $this->unbind($allowedValue);
  99942. }
  99943. }
  99944. }
  99945. $this->name = $name;
  99946. $this->description = $description;
  99947. $this->isRequired = $isRequired;
  99948. $this->default = $default;
  99949. $this->allowedTypes = $allowedTypes;
  99950. $this->allowedValues = $allowedValues;
  99951. if (null !== $normalizer) {
  99952. $this->normalizer = $this->unbind($normalizer);
  99953. } else {
  99954. $this->normalizer = null;
  99955. }
  99956. }
  99957. public function getName(): string
  99958. {
  99959. return $this->name;
  99960. }
  99961. public function getDescription(): string
  99962. {
  99963. return $this->description;
  99964. }
  99965. public function hasDefault(): bool
  99966. {
  99967. return !$this->isRequired;
  99968. }
  99969. public function getDefault()
  99970. {
  99971. if (!$this->hasDefault()) {
  99972. throw new \LogicException('No default value defined.');
  99973. }
  99974. return $this->default;
  99975. }
  99976. public function getAllowedTypes(): ?array
  99977. {
  99978. return $this->allowedTypes;
  99979. }
  99980. public function getAllowedValues(): ?array
  99981. {
  99982. return $this->allowedValues;
  99983. }
  99984. public function getNormalizer(): ?\Closure
  99985. {
  99986. return $this->normalizer;
  99987. }
  99988. private function unbind(\Closure $closure): \Closure
  99989. {
  99990. return $closure->bindTo(null);
  99991. }
  99992. }
  99993. <?php
  99994. declare(strict_types=1);
  99995. namespace PhpCsFixer\FixerConfiguration;
  99996. interface FixerOptionInterface
  99997. {
  99998. public function getName(): string;
  99999. public function getDescription(): string;
  100000. public function hasDefault(): bool;
  100001. public function getDefault();
  100002. public function getAllowedTypes(): ?array;
  100003. public function getAllowedValues(): ?array;
  100004. public function getNormalizer(): ?\Closure;
  100005. }
  100006. <?php
  100007. declare(strict_types=1);
  100008. namespace PhpCsFixer\FixerConfiguration;
  100009. final class FixerOptionSorter
  100010. {
  100011. public function sort(iterable $options): array
  100012. {
  100013. if (!\is_array($options)) {
  100014. $options = iterator_to_array($options, false);
  100015. }
  100016. usort($options, static fn (FixerOptionInterface $a, FixerOptionInterface $b): int => $a->getName() <=> $b->getName());
  100017. return $options;
  100018. }
  100019. }
  100020. <?php
  100021. declare(strict_types=1);
  100022. namespace PhpCsFixer\FixerConfiguration;
  100023. final class FixerOptionBuilder
  100024. {
  100025. private string $name;
  100026. private string $description;
  100027. private $default;
  100028. private bool $isRequired = true;
  100029. private ?array $allowedTypes = null;
  100030. private ?array $allowedValues = null;
  100031. private ?\Closure $normalizer = null;
  100032. private ?string $deprecationMessage = null;
  100033. public function __construct(string $name, string $description)
  100034. {
  100035. $this->name = $name;
  100036. $this->description = $description;
  100037. $this->default = null;
  100038. }
  100039. public function setDefault($default): self
  100040. {
  100041. $this->default = $default;
  100042. $this->isRequired = false;
  100043. return $this;
  100044. }
  100045. public function setAllowedTypes(array $allowedTypes): self
  100046. {
  100047. $this->allowedTypes = $allowedTypes;
  100048. return $this;
  100049. }
  100050. public function setAllowedValues(array $allowedValues): self
  100051. {
  100052. $this->allowedValues = $allowedValues;
  100053. return $this;
  100054. }
  100055. public function setNormalizer(\Closure $normalizer): self
  100056. {
  100057. $this->normalizer = $normalizer;
  100058. return $this;
  100059. }
  100060. public function setDeprecationMessage(?string $deprecationMessage): self
  100061. {
  100062. $this->deprecationMessage = $deprecationMessage;
  100063. return $this;
  100064. }
  100065. public function getOption(): FixerOptionInterface
  100066. {
  100067. $option = new FixerOption(
  100068. $this->name,
  100069. $this->description,
  100070. $this->isRequired,
  100071. $this->default,
  100072. $this->allowedTypes,
  100073. $this->allowedValues,
  100074. $this->normalizer
  100075. );
  100076. if (null !== $this->deprecationMessage) {
  100077. $option = new DeprecatedFixerOption($option, $this->deprecationMessage);
  100078. }
  100079. return $option;
  100080. }
  100081. }
  100082. <?php
  100083. declare(strict_types=1);
  100084. namespace PhpCsFixer\FixerConfiguration;
  100085. use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
  100086. final class InvalidOptionsForEnvException extends InvalidOptionsException {}
  100087. <?php
  100088. declare(strict_types=1);
  100089. namespace PhpCsFixer\FixerConfiguration;
  100090. /**
  100091. @readonly
  100092. */
  100093. final class AliasedFixerOption implements FixerOptionInterface
  100094. {
  100095. private FixerOptionInterface $fixerOption;
  100096. private string $alias;
  100097. public function __construct(FixerOptionInterface $fixerOption, string $alias)
  100098. {
  100099. $this->fixerOption = $fixerOption;
  100100. $this->alias = $alias;
  100101. }
  100102. public function getAlias(): string
  100103. {
  100104. return $this->alias;
  100105. }
  100106. public function getName(): string
  100107. {
  100108. return $this->fixerOption->getName();
  100109. }
  100110. public function getDescription(): string
  100111. {
  100112. return $this->fixerOption->getDescription();
  100113. }
  100114. public function hasDefault(): bool
  100115. {
  100116. return $this->fixerOption->hasDefault();
  100117. }
  100118. public function getDefault()
  100119. {
  100120. return $this->fixerOption->getDefault();
  100121. }
  100122. public function getAllowedTypes(): ?array
  100123. {
  100124. return $this->fixerOption->getAllowedTypes();
  100125. }
  100126. public function getAllowedValues(): ?array
  100127. {
  100128. return $this->fixerOption->getAllowedValues();
  100129. }
  100130. public function getNormalizer(): ?\Closure
  100131. {
  100132. return $this->fixerOption->getNormalizer();
  100133. }
  100134. }
  100135. <?php
  100136. declare(strict_types=1);
  100137. namespace PhpCsFixer\FixerConfiguration;
  100138. final class AliasedFixerOptionBuilder
  100139. {
  100140. private FixerOptionBuilder $optionBuilder;
  100141. private string $alias;
  100142. public function __construct(FixerOptionBuilder $optionBuilder, string $alias)
  100143. {
  100144. $this->optionBuilder = $optionBuilder;
  100145. $this->alias = $alias;
  100146. }
  100147. public function setDefault($default): self
  100148. {
  100149. $this->optionBuilder->setDefault($default);
  100150. return $this;
  100151. }
  100152. public function setAllowedTypes(array $allowedTypes): self
  100153. {
  100154. $this->optionBuilder->setAllowedTypes($allowedTypes);
  100155. return $this;
  100156. }
  100157. public function setAllowedValues(array $allowedValues): self
  100158. {
  100159. $this->optionBuilder->setAllowedValues($allowedValues);
  100160. return $this;
  100161. }
  100162. public function setNormalizer(\Closure $normalizer): self
  100163. {
  100164. $this->optionBuilder->setNormalizer($normalizer);
  100165. return $this;
  100166. }
  100167. public function getOption(): AliasedFixerOption
  100168. {
  100169. return new AliasedFixerOption(
  100170. $this->optionBuilder->getOption(),
  100171. $this->alias
  100172. );
  100173. }
  100174. }
  100175. <?php
  100176. declare(strict_types=1);
  100177. namespace PhpCsFixer\FixerConfiguration;
  100178. interface FixerConfigurationResolverInterface
  100179. {
  100180. public function getOptions(): array;
  100181. public function resolve(array $configuration): array;
  100182. }
  100183. <?php
  100184. declare(strict_types=1);
  100185. namespace PhpCsFixer\FixerConfiguration;
  100186. /**
  100187. @readonly
  100188. */
  100189. final class DeprecatedFixerOption implements DeprecatedFixerOptionInterface
  100190. {
  100191. private FixerOptionInterface $option;
  100192. private string $deprecationMessage;
  100193. public function __construct(FixerOptionInterface $option, string $deprecationMessage)
  100194. {
  100195. $this->option = $option;
  100196. $this->deprecationMessage = $deprecationMessage;
  100197. }
  100198. public function getName(): string
  100199. {
  100200. return $this->option->getName();
  100201. }
  100202. public function getDescription(): string
  100203. {
  100204. return $this->option->getDescription();
  100205. }
  100206. public function hasDefault(): bool
  100207. {
  100208. return $this->option->hasDefault();
  100209. }
  100210. public function getDefault()
  100211. {
  100212. return $this->option->getDefault();
  100213. }
  100214. public function getAllowedTypes(): ?array
  100215. {
  100216. return $this->option->getAllowedTypes();
  100217. }
  100218. public function getAllowedValues(): ?array
  100219. {
  100220. return $this->option->getAllowedValues();
  100221. }
  100222. public function getNormalizer(): ?\Closure
  100223. {
  100224. return $this->option->getNormalizer();
  100225. }
  100226. public function getDeprecationMessage(): string
  100227. {
  100228. return $this->deprecationMessage;
  100229. }
  100230. }
  100231. <?php
  100232. declare(strict_types=1);
  100233. namespace PhpCsFixer;
  100234. final class ExecutorWithoutErrorHandlerException extends \RuntimeException {}
  100235. <?php
  100236. declare(strict_types=1);
  100237. namespace PhpCsFixer;
  100238. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  100239. interface ParallelAwareConfigInterface extends ConfigInterface
  100240. {
  100241. public function getParallelConfig(): ParallelConfig;
  100242. public function setParallelConfig(ParallelConfig $config): ConfigInterface;
  100243. }
  100244. <?php
  100245. declare(strict_types=1);
  100246. namespace PhpCsFixer;
  100247. use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
  100248. use PhpCsFixer\Tokenizer\Tokens;
  100249. abstract class AbstractFopenFlagFixer extends AbstractFunctionReferenceFixer
  100250. {
  100251. public function isCandidate(Tokens $tokens): bool
  100252. {
  100253. return $tokens->isAllTokenKindsFound([T_STRING, T_CONSTANT_ENCAPSED_STRING]);
  100254. }
  100255. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  100256. {
  100257. $argumentsAnalyzer = new ArgumentsAnalyzer();
  100258. $index = 0;
  100259. $end = $tokens->count() - 1;
  100260. while (true) {
  100261. $candidate = $this->find('fopen', $tokens, $index, $end);
  100262. if (null === $candidate) {
  100263. break;
  100264. }
  100265. $index = $candidate[1];
  100266. $arguments = $argumentsAnalyzer->getArguments(
  100267. $tokens,
  100268. $index,
  100269. $candidate[2]
  100270. );
  100271. $argumentsCount = \count($arguments);
  100272. if ($argumentsCount < 2 || $argumentsCount > 4) {
  100273. continue;
  100274. }
  100275. $argumentStartIndex = array_keys($arguments)[1];
  100276. $this->fixFopenFlagToken(
  100277. $tokens,
  100278. $argumentStartIndex,
  100279. $arguments[$argumentStartIndex]
  100280. );
  100281. }
  100282. }
  100283. abstract protected function fixFopenFlagToken(Tokens $tokens, int $argumentStartIndex, int $argumentEndIndex): void;
  100284. protected function isValidModeString(string $mode): bool
  100285. {
  100286. $modeLength = \strlen($mode);
  100287. if ($modeLength < 1 || $modeLength > 13) {
  100288. return false;
  100289. }
  100290. $validFlags = [
  100291. 'a' => true,
  100292. 'b' => true,
  100293. 'c' => true,
  100294. 'e' => true,
  100295. 'r' => true,
  100296. 't' => true,
  100297. 'w' => true,
  100298. 'x' => true,
  100299. ];
  100300. if (!isset($validFlags[$mode[0]])) {
  100301. return false;
  100302. }
  100303. unset($validFlags[$mode[0]]);
  100304. for ($i = 1; $i < $modeLength; ++$i) {
  100305. if (isset($validFlags[$mode[$i]])) {
  100306. unset($validFlags[$mode[$i]]);
  100307. continue;
  100308. }
  100309. if ('+' !== $mode[$i]
  100310. || (
  100311. 'a' !== $mode[$i - 1]
  100312. && 'c' !== $mode[$i - 1]
  100313. && 'r' !== $mode[$i - 1]
  100314. && 'w' !== $mode[$i - 1]
  100315. && 'x' !== $mode[$i - 1]
  100316. )
  100317. ) {
  100318. return false;
  100319. }
  100320. }
  100321. return true;
  100322. }
  100323. }
  100324. <?php
  100325. declare(strict_types=1);
  100326. namespace PhpCsFixer;
  100327. final class PharChecker implements PharCheckerInterface
  100328. {
  100329. public function checkFileValidity(string $filename): ?string
  100330. {
  100331. try {
  100332. $phar = new \Phar($filename);
  100333. unset($phar);
  100334. } catch (\Exception $e) {
  100335. if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
  100336. throw $e;
  100337. }
  100338. return 'Failed to create Phar instance. '.$e->getMessage();
  100339. }
  100340. return null;
  100341. }
  100342. }
  100343. <?php
  100344. declare(strict_types=1);
  100345. namespace PhpCsFixer\Differ;
  100346. use SebastianBergmann\Diff\Differ;
  100347. use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
  100348. /**
  100349. @readonly
  100350. */
  100351. final class FullDiffer implements DifferInterface
  100352. {
  100353. private Differ $differ;
  100354. public function __construct()
  100355. {
  100356. $this->differ = new Differ(new StrictUnifiedDiffOutputBuilder([
  100357. 'collapseRanges' => false,
  100358. 'commonLineThreshold' => 100,
  100359. 'contextLines' => 100,
  100360. 'fromFile' => 'Original',
  100361. 'toFile' => 'New',
  100362. ]));
  100363. }
  100364. public function diff(string $old, string $new, ?\SplFileInfo $file = null): string
  100365. {
  100366. return $this->differ->diff($old, $new);
  100367. }
  100368. }
  100369. <?php
  100370. declare(strict_types=1);
  100371. namespace PhpCsFixer\Differ;
  100372. use PhpCsFixer\Preg;
  100373. use Symfony\Component\Console\Formatter\OutputFormatter;
  100374. /**
  100375. @readonly
  100376. */
  100377. final class DiffConsoleFormatter
  100378. {
  100379. private bool $isDecoratedOutput;
  100380. private string $template;
  100381. public function __construct(bool $isDecoratedOutput, string $template = '%s')
  100382. {
  100383. $this->isDecoratedOutput = $isDecoratedOutput;
  100384. $this->template = $template;
  100385. }
  100386. public function format(string $diff, string $lineTemplate = '%s'): string
  100387. {
  100388. $isDecorated = $this->isDecoratedOutput;
  100389. $template = $isDecorated
  100390. ? $this->template
  100391. : Preg::replace('/<[^<>]+>/', '', $this->template);
  100392. return \sprintf(
  100393. $template,
  100394. implode(
  100395. PHP_EOL,
  100396. array_map(
  100397. static function (string $line) use ($isDecorated, $lineTemplate): string {
  100398. if ($isDecorated) {
  100399. $count = 0;
  100400. $line = Preg::replaceCallback(
  100401. '/^([+\-@].*)/',
  100402. static function (array $matches): string {
  100403. if ('+' === $matches[0][0]) {
  100404. $colour = 'green';
  100405. } elseif ('-' === $matches[0][0]) {
  100406. $colour = 'red';
  100407. } else {
  100408. $colour = 'cyan';
  100409. }
  100410. return \sprintf('<fg=%s>%s</fg=%s>', $colour, OutputFormatter::escape($matches[0]), $colour);
  100411. },
  100412. $line,
  100413. 1,
  100414. $count
  100415. );
  100416. if (0 === $count) {
  100417. $line = OutputFormatter::escape($line);
  100418. }
  100419. }
  100420. return \sprintf($lineTemplate, $line);
  100421. },
  100422. Preg::split('#\R#u', $diff)
  100423. )
  100424. )
  100425. );
  100426. }
  100427. }
  100428. <?php
  100429. declare(strict_types=1);
  100430. namespace PhpCsFixer\Differ;
  100431. interface DifferInterface
  100432. {
  100433. public function diff(string $old, string $new, ?\SplFileInfo $file = null): string;
  100434. }
  100435. <?php
  100436. declare(strict_types=1);
  100437. namespace PhpCsFixer\Differ;
  100438. final class NullDiffer implements DifferInterface
  100439. {
  100440. public function diff(string $old, string $new, ?\SplFileInfo $file = null): string
  100441. {
  100442. return '';
  100443. }
  100444. }
  100445. <?php
  100446. declare(strict_types=1);
  100447. namespace PhpCsFixer\Differ;
  100448. use PhpCsFixer\Preg;
  100449. use SebastianBergmann\Diff\Differ;
  100450. use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
  100451. final class UnifiedDiffer implements DifferInterface
  100452. {
  100453. public function diff(string $old, string $new, ?\SplFileInfo $file = null): string
  100454. {
  100455. if (null === $file) {
  100456. $options = [
  100457. 'fromFile' => 'Original',
  100458. 'toFile' => 'New',
  100459. ];
  100460. } else {
  100461. $filePath = $file->getRealPath();
  100462. if (Preg::match('/\s/', $filePath)) {
  100463. $filePath = '"'.$filePath.'"';
  100464. }
  100465. $options = [
  100466. 'fromFile' => $filePath,
  100467. 'toFile' => $filePath,
  100468. ];
  100469. }
  100470. $differ = new Differ(new StrictUnifiedDiffOutputBuilder($options));
  100471. return $differ->diff($old, $new);
  100472. }
  100473. }
  100474. <?php
  100475. declare(strict_types=1);
  100476. namespace PhpCsFixer;
  100477. final class FixerNameValidator
  100478. {
  100479. public function isValid(string $name, bool $isCustom): bool
  100480. {
  100481. if (!$isCustom) {
  100482. return Preg::match('/^[a-z][a-z0-9_]*$/', $name);
  100483. }
  100484. return Preg::match('/^[A-Z][a-zA-Z0-9]*\/[a-z][a-z0-9_]*$/', $name);
  100485. }
  100486. }
  100487. <?php
  100488. declare(strict_types=1);
  100489. namespace PhpCsFixer;
  100490. use PhpCsFixer\Fixer\FixerInterface;
  100491. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  100492. use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
  100493. class Config implements ConfigInterface, ParallelAwareConfigInterface, UnsupportedPhpVersionAllowedConfigInterface
  100494. {
  100495. private string $cacheFile = '.php-cs-fixer.cache';
  100496. private array $customFixers = [];
  100497. private ?iterable $finder = null;
  100498. private string $format;
  100499. private bool $hideProgress = false;
  100500. private string $indent = ' ';
  100501. private bool $isRiskyAllowed = false;
  100502. private string $lineEnding = "\n";
  100503. private string $name;
  100504. private ParallelConfig $parallelConfig;
  100505. private ?string $phpExecutable = null;
  100506. /**
  100507. @TODO:
  100508. */
  100509. private array $rules;
  100510. private bool $usingCache = true;
  100511. private bool $isUnsupportedPhpVersionAllowed = false;
  100512. public function __construct(string $name = 'default')
  100513. {
  100514. if (Utils::isFutureModeEnabled()) {
  100515. $this->name = $name.' (future mode)';
  100516. $this->rules = ['@PER-CS' => true];
  100517. $this->format = '@auto';
  100518. } else {
  100519. $this->name = $name;
  100520. $this->rules = ['@PSR12' => true];
  100521. $this->format = 'txt';
  100522. }
  100523. if (Utils::isFutureModeEnabled() || filter_var(getenv('PHP_CS_FIXER_PARALLEL'), FILTER_VALIDATE_BOOL)) {
  100524. $this->parallelConfig = ParallelConfigFactory::detect();
  100525. } else {
  100526. $this->parallelConfig = ParallelConfigFactory::sequential();
  100527. }
  100528. if (false !== getenv('PHP_CS_FIXER_IGNORE_ENV')) {
  100529. $this->isUnsupportedPhpVersionAllowed = filter_var(getenv('PHP_CS_FIXER_IGNORE_ENV'), FILTER_VALIDATE_BOOL);
  100530. }
  100531. }
  100532. public function getCacheFile(): string
  100533. {
  100534. return $this->cacheFile;
  100535. }
  100536. public function getCustomFixers(): array
  100537. {
  100538. return $this->customFixers;
  100539. }
  100540. public function getFinder(): iterable
  100541. {
  100542. $this->finder ??= new Finder();
  100543. return $this->finder;
  100544. }
  100545. public function getFormat(): string
  100546. {
  100547. return $this->format;
  100548. }
  100549. public function getHideProgress(): bool
  100550. {
  100551. return $this->hideProgress;
  100552. }
  100553. public function getIndent(): string
  100554. {
  100555. return $this->indent;
  100556. }
  100557. public function getLineEnding(): string
  100558. {
  100559. return $this->lineEnding;
  100560. }
  100561. public function getName(): string
  100562. {
  100563. return $this->name;
  100564. }
  100565. public function getParallelConfig(): ParallelConfig
  100566. {
  100567. return $this->parallelConfig;
  100568. }
  100569. public function getPhpExecutable(): ?string
  100570. {
  100571. return $this->phpExecutable;
  100572. }
  100573. public function getRiskyAllowed(): bool
  100574. {
  100575. return $this->isRiskyAllowed;
  100576. }
  100577. public function getRules(): array
  100578. {
  100579. return $this->rules;
  100580. }
  100581. public function getUsingCache(): bool
  100582. {
  100583. return $this->usingCache;
  100584. }
  100585. public function getUnsupportedPhpVersionAllowed(): bool
  100586. {
  100587. return $this->isUnsupportedPhpVersionAllowed;
  100588. }
  100589. public function registerCustomFixers(iterable $fixers): ConfigInterface
  100590. {
  100591. foreach ($fixers as $fixer) {
  100592. $this->addCustomFixer($fixer);
  100593. }
  100594. return $this;
  100595. }
  100596. public function setCacheFile(string $cacheFile): ConfigInterface
  100597. {
  100598. $this->cacheFile = $cacheFile;
  100599. return $this;
  100600. }
  100601. public function setFinder(iterable $finder): ConfigInterface
  100602. {
  100603. $this->finder = $finder;
  100604. return $this;
  100605. }
  100606. public function setFormat(string $format): ConfigInterface
  100607. {
  100608. $this->format = $format;
  100609. return $this;
  100610. }
  100611. public function setHideProgress(bool $hideProgress): ConfigInterface
  100612. {
  100613. $this->hideProgress = $hideProgress;
  100614. return $this;
  100615. }
  100616. public function setIndent(string $indent): ConfigInterface
  100617. {
  100618. $this->indent = $indent;
  100619. return $this;
  100620. }
  100621. public function setLineEnding(string $lineEnding): ConfigInterface
  100622. {
  100623. $this->lineEnding = $lineEnding;
  100624. return $this;
  100625. }
  100626. public function setParallelConfig(ParallelConfig $config): ConfigInterface
  100627. {
  100628. $this->parallelConfig = $config;
  100629. return $this;
  100630. }
  100631. public function setPhpExecutable(?string $phpExecutable): ConfigInterface
  100632. {
  100633. $this->phpExecutable = $phpExecutable;
  100634. return $this;
  100635. }
  100636. public function setRiskyAllowed(bool $isRiskyAllowed): ConfigInterface
  100637. {
  100638. $this->isRiskyAllowed = $isRiskyAllowed;
  100639. return $this;
  100640. }
  100641. public function setRules(array $rules): ConfigInterface
  100642. {
  100643. $this->rules = $rules;
  100644. return $this;
  100645. }
  100646. public function setUsingCache(bool $usingCache): ConfigInterface
  100647. {
  100648. $this->usingCache = $usingCache;
  100649. return $this;
  100650. }
  100651. public function setUnsupportedPhpVersionAllowed(bool $isUnsupportedPhpVersionAllowed): ConfigInterface
  100652. {
  100653. $this->isUnsupportedPhpVersionAllowed = $isUnsupportedPhpVersionAllowed;
  100654. return $this;
  100655. }
  100656. private function addCustomFixer(FixerInterface $fixer): void
  100657. {
  100658. $this->customFixers[] = $fixer;
  100659. }
  100660. }
  100661. <?php
  100662. declare(strict_types=1);
  100663. namespace PhpCsFixer;
  100664. interface UnsupportedPhpVersionAllowedConfigInterface extends ConfigInterface
  100665. {
  100666. public function getUnsupportedPhpVersionAllowed(): bool;
  100667. public function setUnsupportedPhpVersionAllowed(bool $isUnsupportedPhpVersionAllowed): ConfigInterface;
  100668. }
  100669. <?php
  100670. declare(strict_types=1);
  100671. namespace PhpCsFixer\Doctrine\Annotation;
  100672. use PhpCsFixer\Preg;
  100673. use PhpCsFixer\Tokenizer\Token as PhpToken;
  100674. /**
  100675. @extends
  100676. */
  100677. final class Tokens extends \SplFixedArray
  100678. {
  100679. public static function createFromDocComment(PhpToken $input, array $ignoredTags = []): self
  100680. {
  100681. if (!$input->isGivenKind(T_DOC_COMMENT)) {
  100682. throw new \InvalidArgumentException('Input must be a T_DOC_COMMENT token.');
  100683. }
  100684. $tokens = [];
  100685. $content = $input->getContent();
  100686. $ignoredTextPosition = 0;
  100687. $currentPosition = 0;
  100688. $token = null;
  100689. while (false !== $nextAtPosition = strpos($content, '@', $currentPosition)) {
  100690. if (0 !== $nextAtPosition && !Preg::match('/\s/', $content[$nextAtPosition - 1])) {
  100691. $currentPosition = $nextAtPosition + 1;
  100692. continue;
  100693. }
  100694. $lexer = new DocLexer();
  100695. $lexer->setInput(substr($content, $nextAtPosition));
  100696. $scannedTokens = [];
  100697. $index = 0;
  100698. $nbScannedTokensToUse = 0;
  100699. $nbScopes = 0;
  100700. while (null !== $token = $lexer->peek()) {
  100701. if (0 === $index && !$token->isType(DocLexer::T_AT)) {
  100702. break;
  100703. }
  100704. if (1 === $index) {
  100705. if (!$token->isType(DocLexer::T_IDENTIFIER) || \in_array($token->getContent(), $ignoredTags, true)) {
  100706. break;
  100707. }
  100708. $nbScannedTokensToUse = 2;
  100709. }
  100710. if ($index >= 2 && 0 === $nbScopes && !$token->isType([DocLexer::T_NONE, DocLexer::T_OPEN_PARENTHESIS])) {
  100711. break;
  100712. }
  100713. $scannedTokens[] = $token;
  100714. if ($token->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  100715. ++$nbScopes;
  100716. } elseif ($token->isType(DocLexer::T_CLOSE_PARENTHESIS)) {
  100717. if (0 === --$nbScopes) {
  100718. $nbScannedTokensToUse = \count($scannedTokens);
  100719. break;
  100720. }
  100721. }
  100722. ++$index;
  100723. }
  100724. if (0 !== $nbScopes) {
  100725. break;
  100726. }
  100727. if (0 !== $nbScannedTokensToUse) {
  100728. $ignoredTextLength = $nextAtPosition - $ignoredTextPosition;
  100729. if (0 !== $ignoredTextLength) {
  100730. $tokens[] = new Token(DocLexer::T_NONE, substr($content, $ignoredTextPosition, $ignoredTextLength));
  100731. }
  100732. $lastTokenEndIndex = 0;
  100733. foreach (\array_slice($scannedTokens, 0, $nbScannedTokensToUse) as $scannedToken) {
  100734. $token = $scannedToken->isType(DocLexer::T_STRING)
  100735. ? new Token(
  100736. $scannedToken->getType(),
  100737. '"'.str_replace('"', '""', $scannedToken->getContent()).'"',
  100738. $scannedToken->getPosition()
  100739. )
  100740. : $scannedToken;
  100741. $missingTextLength = $token->getPosition() - $lastTokenEndIndex;
  100742. if ($missingTextLength > 0) {
  100743. $tokens[] = new Token(DocLexer::T_NONE, substr(
  100744. $content,
  100745. $nextAtPosition + $lastTokenEndIndex,
  100746. $missingTextLength
  100747. ));
  100748. }
  100749. $tokens[] = new Token($token->getType(), $token->getContent());
  100750. $lastTokenEndIndex = $token->getPosition() + \strlen($token->getContent());
  100751. }
  100752. $currentPosition = $ignoredTextPosition = $nextAtPosition + $token->getPosition() + \strlen($token->getContent());
  100753. } else {
  100754. $currentPosition = $nextAtPosition + 1;
  100755. }
  100756. }
  100757. if ($ignoredTextPosition < \strlen($content)) {
  100758. $tokens[] = new Token(DocLexer::T_NONE, substr($content, $ignoredTextPosition));
  100759. }
  100760. return self::fromArray($tokens);
  100761. }
  100762. public static function fromArray($array, $saveIndices = null): self
  100763. {
  100764. $tokens = new self(\count($array));
  100765. if (null === $saveIndices || $saveIndices) {
  100766. foreach ($array as $key => $val) {
  100767. $tokens[$key] = $val;
  100768. }
  100769. } else {
  100770. $index = 0;
  100771. foreach ($array as $val) {
  100772. $tokens[$index++] = $val;
  100773. }
  100774. }
  100775. return $tokens;
  100776. }
  100777. public function getNextMeaningfulToken(int $index): ?int
  100778. {
  100779. return $this->getMeaningfulTokenSibling($index, 1);
  100780. }
  100781. public function getPreviousMeaningfulToken(int $index): ?int
  100782. {
  100783. return $this->getMeaningfulTokenSibling($index, -1);
  100784. }
  100785. public function getAnnotationEnd(int $index): ?int
  100786. {
  100787. $currentIndex = null;
  100788. if (isset($this[$index + 2])) {
  100789. if ($this[$index + 2]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  100790. $currentIndex = $index + 2;
  100791. } elseif (
  100792. isset($this[$index + 3])
  100793. && $this[$index + 2]->isType(DocLexer::T_NONE)
  100794. && $this[$index + 3]->isType(DocLexer::T_OPEN_PARENTHESIS)
  100795. && Preg::match('/^(\R\s*\*\s*)*\s*$/', $this[$index + 2]->getContent())
  100796. ) {
  100797. $currentIndex = $index + 3;
  100798. }
  100799. }
  100800. if (null !== $currentIndex) {
  100801. $level = 0;
  100802. for ($max = \count($this); $currentIndex < $max; ++$currentIndex) {
  100803. if ($this[$currentIndex]->isType(DocLexer::T_OPEN_PARENTHESIS)) {
  100804. ++$level;
  100805. } elseif ($this[$currentIndex]->isType(DocLexer::T_CLOSE_PARENTHESIS)) {
  100806. --$level;
  100807. }
  100808. if (0 === $level) {
  100809. return $currentIndex;
  100810. }
  100811. }
  100812. return null;
  100813. }
  100814. return $index + 1;
  100815. }
  100816. public function getCode(): string
  100817. {
  100818. $code = '';
  100819. foreach ($this as $token) {
  100820. $code .= $token->getContent();
  100821. }
  100822. return $code;
  100823. }
  100824. public function insertAt(int $index, Token $token): void
  100825. {
  100826. $this->setSize($this->getSize() + 1);
  100827. for ($i = $this->getSize() - 1; $i > $index; --$i) {
  100828. $this[$i] = $this[$i - 1] ?? new Token();
  100829. }
  100830. $this[$index] = $token;
  100831. }
  100832. public function offsetSet($index, $token): void
  100833. {
  100834. if (null === $token) {
  100835. throw new \InvalidArgumentException('Token must be an instance of PhpCsFixer\Doctrine\Annotation\Token, "null" given.');
  100836. }
  100837. if (!$token instanceof Token) {
  100838. $type = \gettype($token);
  100839. if ('object' === $type) {
  100840. $type = \get_class($token);
  100841. }
  100842. throw new \InvalidArgumentException(\sprintf('Token must be an instance of PhpCsFixer\Doctrine\Annotation\Token, "%s" given.', $type));
  100843. }
  100844. parent::offsetSet($index, $token);
  100845. }
  100846. public function offsetUnset($index): void
  100847. {
  100848. if (!isset($this[$index])) {
  100849. throw new \OutOfBoundsException(\sprintf('Index "%s" is invalid or does not exist.', $index));
  100850. }
  100851. $max = \count($this) - 1;
  100852. while ($index < $max) {
  100853. $this[$index] = $this[$index + 1];
  100854. ++$index;
  100855. }
  100856. parent::offsetUnset($index);
  100857. $this->setSize($max);
  100858. }
  100859. private function getMeaningfulTokenSibling(int $index, int $direction): ?int
  100860. {
  100861. while (true) {
  100862. $index += $direction;
  100863. if (!$this->offsetExists($index)) {
  100864. break;
  100865. }
  100866. if (!$this[$index]->isType(DocLexer::T_NONE)) {
  100867. return $index;
  100868. }
  100869. }
  100870. return null;
  100871. }
  100872. }
  100873. <?php
  100874. declare(strict_types=1);
  100875. namespace PhpCsFixer\Doctrine\Annotation;
  100876. final class Token
  100877. {
  100878. private int $type;
  100879. private string $content;
  100880. private int $position;
  100881. public function __construct(int $type = DocLexer::T_NONE, string $content = '', int $position = 0)
  100882. {
  100883. $this->type = $type;
  100884. $this->content = $content;
  100885. $this->position = $position;
  100886. }
  100887. public function getType(): int
  100888. {
  100889. return $this->type;
  100890. }
  100891. public function setType(int $type): void
  100892. {
  100893. $this->type = $type;
  100894. }
  100895. public function getContent(): string
  100896. {
  100897. return $this->content;
  100898. }
  100899. public function setContent(string $content): void
  100900. {
  100901. $this->content = $content;
  100902. }
  100903. public function getPosition(): int
  100904. {
  100905. return $this->position;
  100906. }
  100907. public function isType($types): bool
  100908. {
  100909. if (!\is_array($types)) {
  100910. $types = [$types];
  100911. }
  100912. return \in_array($this->getType(), $types, true);
  100913. }
  100914. public function clear(): void
  100915. {
  100916. $this->setContent('');
  100917. }
  100918. }
  100919. <?php
  100920. declare(strict_types=1);
  100921. namespace PhpCsFixer\Doctrine\Annotation;
  100922. use PhpCsFixer\Preg;
  100923. final class DocLexer
  100924. {
  100925. public const T_NONE = 1;
  100926. public const T_INTEGER = 2;
  100927. public const T_STRING = 3;
  100928. public const T_FLOAT = 4;
  100929. public const T_IDENTIFIER = 100;
  100930. public const T_AT = 101;
  100931. public const T_CLOSE_CURLY_BRACES = 102;
  100932. public const T_CLOSE_PARENTHESIS = 103;
  100933. public const T_COMMA = 104;
  100934. public const T_EQUALS = 105;
  100935. public const T_FALSE = 106;
  100936. public const T_NAMESPACE_SEPARATOR = 107;
  100937. public const T_OPEN_CURLY_BRACES = 108;
  100938. public const T_OPEN_PARENTHESIS = 109;
  100939. public const T_TRUE = 110;
  100940. public const T_NULL = 111;
  100941. public const T_COLON = 112;
  100942. public const T_MINUS = 113;
  100943. private array $noCase = [
  100944. '@' => self::T_AT,
  100945. ',' => self::T_COMMA,
  100946. '(' => self::T_OPEN_PARENTHESIS,
  100947. ')' => self::T_CLOSE_PARENTHESIS,
  100948. '{' => self::T_OPEN_CURLY_BRACES,
  100949. '}' => self::T_CLOSE_CURLY_BRACES,
  100950. '=' => self::T_EQUALS,
  100951. ':' => self::T_COLON,
  100952. '-' => self::T_MINUS,
  100953. '\\' => self::T_NAMESPACE_SEPARATOR,
  100954. ];
  100955. private array $tokens = [];
  100956. private int $position = 0;
  100957. private int $peek = 0;
  100958. private ?string $regex = null;
  100959. public function setInput(string $input): void
  100960. {
  100961. $this->tokens = [];
  100962. $this->reset();
  100963. $this->scan($input);
  100964. }
  100965. public function reset(): void
  100966. {
  100967. $this->peek = 0;
  100968. $this->position = 0;
  100969. }
  100970. public function peek(): ?Token
  100971. {
  100972. if (isset($this->tokens[$this->position + $this->peek])) {
  100973. return $this->tokens[$this->position + $this->peek++];
  100974. }
  100975. return null;
  100976. }
  100977. private function getCatchablePatterns(): array
  100978. {
  100979. return [
  100980. '[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
  100981. '(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
  100982. '"(?:""|[^"])*+"',
  100983. ];
  100984. }
  100985. private function getNonCatchablePatterns(): array
  100986. {
  100987. return ['\s+', '\*+', '(.)'];
  100988. }
  100989. private function getType(string &$value): int
  100990. {
  100991. $type = self::T_NONE;
  100992. if ('"' === $value[0]) {
  100993. $value = str_replace('""', '"', substr($value, 1, \strlen($value) - 2));
  100994. return self::T_STRING;
  100995. }
  100996. if (isset($this->noCase[$value])) {
  100997. return $this->noCase[$value];
  100998. }
  100999. if ('_' === $value[0] || '\\' === $value[0] || !Preg::match('/[^A-Za-z]/', $value[0])) {
  101000. return self::T_IDENTIFIER;
  101001. }
  101002. if (is_numeric($value)) {
  101003. return str_contains($value, '.') || false !== stripos($value, 'e')
  101004. ? self::T_FLOAT : self::T_INTEGER;
  101005. }
  101006. return $type;
  101007. }
  101008. private function scan(string $input): void
  101009. {
  101010. $this->regex ??= \sprintf(
  101011. '/(%s)|%s/%s',
  101012. implode(')|(', $this->getCatchablePatterns()),
  101013. implode('|', $this->getNonCatchablePatterns()),
  101014. 'iu'
  101015. );
  101016. $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
  101017. $matches = Preg::split($this->regex, $input, -1, $flags);
  101018. foreach ($matches as $match) {
  101019. $firstMatch = $match[0];
  101020. $type = $this->getType($firstMatch);
  101021. $this->tokens[] = new Token($type, $firstMatch, (int) $match[1]);
  101022. }
  101023. }
  101024. }
  101025. <?php
  101026. declare(strict_types=1);
  101027. namespace PhpCsFixer;
  101028. final class ExecutorWithoutErrorHandler
  101029. {
  101030. private function __construct() {}
  101031. /**
  101032. @template
  101033. */
  101034. public static function execute(callable $callback)
  101035. {
  101036. $error = null;
  101037. set_error_handler(static function (int $errorNumber, string $errorString, string $errorFile, int $errorLine) use (&$error): bool {
  101038. $error = $errorString;
  101039. return true;
  101040. });
  101041. try {
  101042. $result = $callback();
  101043. } finally {
  101044. restore_error_handler();
  101045. }
  101046. if (null !== $error) {
  101047. throw new ExecutorWithoutErrorHandlerException($error);
  101048. }
  101049. return $result;
  101050. }
  101051. }
  101052. <?php
  101053. declare(strict_types=1);
  101054. namespace PhpCsFixer;
  101055. /**
  101056. @readonly
  101057. */
  101058. final class WordMatcher
  101059. {
  101060. private array $candidates;
  101061. public function __construct(array $candidates)
  101062. {
  101063. $this->candidates = $candidates;
  101064. }
  101065. public function match(string $needle): ?string
  101066. {
  101067. $word = null;
  101068. $distance = ceil(\strlen($needle) * 0.35);
  101069. foreach ($this->candidates as $candidate) {
  101070. $candidateDistance = levenshtein($needle, $candidate);
  101071. if ($candidateDistance < $distance) {
  101072. $word = $candidate;
  101073. $distance = $candidateDistance;
  101074. }
  101075. }
  101076. return $word;
  101077. }
  101078. }
  101079. <?php
  101080. declare(strict_types=1);
  101081. namespace PhpCsFixer;
  101082. use PhpCsFixer\Fixer\FixerInterface;
  101083. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  101084. use PhpCsFixer\Tokenizer\Tokens;
  101085. abstract class AbstractProxyFixer extends AbstractFixer
  101086. {
  101087. protected array $proxyFixers = [];
  101088. public function __construct()
  101089. {
  101090. foreach (Utils::sortFixers($this->createProxyFixers()) as $proxyFixer) {
  101091. $this->proxyFixers[$proxyFixer->getName()] = $proxyFixer;
  101092. }
  101093. parent::__construct();
  101094. }
  101095. public function isCandidate(Tokens $tokens): bool
  101096. {
  101097. foreach ($this->proxyFixers as $fixer) {
  101098. if ($fixer->isCandidate($tokens)) {
  101099. return true;
  101100. }
  101101. }
  101102. return false;
  101103. }
  101104. public function isRisky(): bool
  101105. {
  101106. foreach ($this->proxyFixers as $fixer) {
  101107. if ($fixer->isRisky()) {
  101108. return true;
  101109. }
  101110. }
  101111. return false;
  101112. }
  101113. public function getPriority(): int
  101114. {
  101115. if (\count($this->proxyFixers) > 1) {
  101116. throw new \LogicException('You need to override this method to provide the priority of combined fixers.');
  101117. }
  101118. return reset($this->proxyFixers)->getPriority();
  101119. }
  101120. public function supports(\SplFileInfo $file): bool
  101121. {
  101122. foreach ($this->proxyFixers as $fixer) {
  101123. if ($fixer->supports($file)) {
  101124. return true;
  101125. }
  101126. }
  101127. return false;
  101128. }
  101129. public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
  101130. {
  101131. parent::setWhitespacesConfig($config);
  101132. foreach ($this->proxyFixers as $fixer) {
  101133. if ($fixer instanceof WhitespacesAwareFixerInterface) {
  101134. $fixer->setWhitespacesConfig($config);
  101135. }
  101136. }
  101137. }
  101138. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  101139. {
  101140. foreach ($this->proxyFixers as $fixer) {
  101141. $fixer->fix($file, $tokens);
  101142. }
  101143. }
  101144. abstract protected function createProxyFixers(): array;
  101145. }
  101146. <?php
  101147. declare(strict_types=1);
  101148. namespace PhpCsFixer;
  101149. final class StdinFileInfo extends \SplFileInfo
  101150. {
  101151. public function __construct()
  101152. {
  101153. parent::__construct(__FILE__);
  101154. }
  101155. public function __toString(): string
  101156. {
  101157. return $this->getRealPath();
  101158. }
  101159. public function getRealPath(): string
  101160. {
  101161. return 'php://stdin';
  101162. }
  101163. public function getATime(): int
  101164. {
  101165. return 0;
  101166. }
  101167. public function getBasename($suffix = null): string
  101168. {
  101169. return $this->getFilename();
  101170. }
  101171. public function getCTime(): int
  101172. {
  101173. return 0;
  101174. }
  101175. public function getExtension(): string
  101176. {
  101177. return '.php';
  101178. }
  101179. public function getFileInfo($class = null): \SplFileInfo
  101180. {
  101181. throw new \BadMethodCallException(\sprintf('Method "%s" is not implemented.', __METHOD__));
  101182. }
  101183. public function getFilename(): string
  101184. {
  101185. return 'stdin.php';
  101186. }
  101187. public function getGroup(): int
  101188. {
  101189. return 0;
  101190. }
  101191. public function getInode(): int
  101192. {
  101193. return 0;
  101194. }
  101195. public function getLinkTarget(): string
  101196. {
  101197. return '';
  101198. }
  101199. public function getMTime(): int
  101200. {
  101201. return 0;
  101202. }
  101203. public function getOwner(): int
  101204. {
  101205. return 0;
  101206. }
  101207. public function getPath(): string
  101208. {
  101209. return '';
  101210. }
  101211. public function getPathInfo($class = null): \SplFileInfo
  101212. {
  101213. throw new \BadMethodCallException(\sprintf('Method "%s" is not implemented.', __METHOD__));
  101214. }
  101215. public function getPathname(): string
  101216. {
  101217. return $this->getFilename();
  101218. }
  101219. public function getPerms(): int
  101220. {
  101221. return 0;
  101222. }
  101223. public function getSize(): int
  101224. {
  101225. return 0;
  101226. }
  101227. public function getType(): string
  101228. {
  101229. return 'file';
  101230. }
  101231. public function isDir(): bool
  101232. {
  101233. return false;
  101234. }
  101235. public function isExecutable(): bool
  101236. {
  101237. return false;
  101238. }
  101239. public function isFile(): bool
  101240. {
  101241. return true;
  101242. }
  101243. public function isLink(): bool
  101244. {
  101245. return false;
  101246. }
  101247. public function isReadable(): bool
  101248. {
  101249. return true;
  101250. }
  101251. public function isWritable(): bool
  101252. {
  101253. return false;
  101254. }
  101255. public function openFile($openMode = 'r', $useIncludePath = false, $context = null): \SplFileObject
  101256. {
  101257. throw new \BadMethodCallException(\sprintf('Method "%s" is not implemented.', __METHOD__));
  101258. }
  101259. }
  101260. <?php
  101261. declare(strict_types=1);
  101262. namespace PhpCsFixer\DocBlock;
  101263. use PhpCsFixer\Preg;
  101264. final class Tag
  101265. {
  101266. public const PSR_STANDARD_TAGS = [
  101267. 'api', 'author', 'category', 'copyright', 'deprecated', 'example',
  101268. 'global', 'internal', 'license', 'link', 'method', 'package', 'param',
  101269. 'property', 'property-read', 'property-write', 'return', 'see',
  101270. 'since', 'subpackage', 'throws', 'todo', 'uses', 'var', 'version',
  101271. ];
  101272. private Line $line;
  101273. private ?string $name = null;
  101274. public function __construct(Line $line)
  101275. {
  101276. $this->line = $line;
  101277. }
  101278. public function getName(): string
  101279. {
  101280. if (null === $this->name) {
  101281. Preg::matchAll('/@[a-zA-Z0-9_-]+(?=\s|$)/', $this->line->getContent(), $matches);
  101282. if (isset($matches[0][0])) {
  101283. $this->name = ltrim($matches[0][0], '@');
  101284. } else {
  101285. $this->name = 'other';
  101286. }
  101287. }
  101288. return $this->name;
  101289. }
  101290. public function setName(string $name): void
  101291. {
  101292. $current = $this->getName();
  101293. if ('other' === $current) {
  101294. throw new \RuntimeException('Cannot set name on unknown tag.');
  101295. }
  101296. $this->line->setContent(Preg::replace("/@{$current}/", "@{$name}", $this->line->getContent(), 1));
  101297. $this->name = $name;
  101298. }
  101299. public function valid(): bool
  101300. {
  101301. return \in_array($this->getName(), self::PSR_STANDARD_TAGS, true);
  101302. }
  101303. }
  101304. <?php
  101305. declare(strict_types=1);
  101306. namespace PhpCsFixer\DocBlock;
  101307. final class TagComparator
  101308. {
  101309. public const DEFAULT_GROUPS = [
  101310. ['deprecated', 'link', 'see', 'since'],
  101311. ['author', 'copyright', 'license'],
  101312. ['category', 'package', 'subpackage'],
  101313. ['property', 'property-read', 'property-write'],
  101314. ];
  101315. public static function shouldBeTogether(Tag $first, Tag $second, array $groups = self::DEFAULT_GROUPS): bool
  101316. {
  101317. @trigger_error('Method '.__METHOD__.' is deprecated and will be removed in version 4.0.', E_USER_DEPRECATED);
  101318. $firstName = $first->getName();
  101319. $secondName = $second->getName();
  101320. if ($firstName === $secondName) {
  101321. return true;
  101322. }
  101323. foreach ($groups as $group) {
  101324. if (\in_array($firstName, $group, true) && \in_array($secondName, $group, true)) {
  101325. return true;
  101326. }
  101327. }
  101328. return false;
  101329. }
  101330. }
  101331. <?php
  101332. declare(strict_types=1);
  101333. namespace PhpCsFixer\DocBlock;
  101334. use PhpCsFixer\Preg;
  101335. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  101336. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  101337. final class Annotation
  101338. {
  101339. private const TAGS = [
  101340. 'extends',
  101341. 'implements',
  101342. 'method',
  101343. 'param',
  101344. 'param-out',
  101345. 'property',
  101346. 'property-read',
  101347. 'property-write',
  101348. 'return',
  101349. 'throws',
  101350. 'type',
  101351. 'var',
  101352. ];
  101353. private array $lines;
  101354. private int $start;
  101355. private int $end;
  101356. private ?Tag $tag = null;
  101357. private ?string $typesContent = null;
  101358. private ?array $types = null;
  101359. private ?NamespaceAnalysis $namespace = null;
  101360. private array $namespaceUses;
  101361. public function __construct(array $lines, $namespace = null, array $namespaceUses = [])
  101362. {
  101363. $this->lines = array_values($lines);
  101364. $this->namespace = $namespace;
  101365. $this->namespaceUses = $namespaceUses;
  101366. $this->start = array_key_first($lines);
  101367. $this->end = array_key_last($lines);
  101368. }
  101369. public function __toString(): string
  101370. {
  101371. return $this->getContent();
  101372. }
  101373. public static function getTagsWithTypes(): array
  101374. {
  101375. return self::TAGS;
  101376. }
  101377. public function getStart(): int
  101378. {
  101379. return $this->start;
  101380. }
  101381. public function getEnd(): int
  101382. {
  101383. return $this->end;
  101384. }
  101385. public function getTag(): Tag
  101386. {
  101387. if (null === $this->tag) {
  101388. $this->tag = new Tag($this->lines[0]);
  101389. }
  101390. return $this->tag;
  101391. }
  101392. public function getTypeExpression(): ?TypeExpression
  101393. {
  101394. $typesContent = $this->getTypesContent();
  101395. return null === $typesContent
  101396. ? null
  101397. : new TypeExpression($typesContent, $this->namespace, $this->namespaceUses);
  101398. }
  101399. public function getVariableName(): ?string
  101400. {
  101401. $type = preg_quote($this->getTypesContent() ?? '', '/');
  101402. $regex = \sprintf(
  101403. '/@%s\s+(%s\s*)?(&\s*)?(\.{3}\s*)?(?<variable>\$%s)(?:.*|$)/',
  101404. $this->tag->getName(),
  101405. $type,
  101406. TypeExpression::REGEX_IDENTIFIER
  101407. );
  101408. if (Preg::match($regex, $this->lines[0]->getContent(), $matches)) {
  101409. return $matches['variable'];
  101410. }
  101411. return null;
  101412. }
  101413. public function getTypes(): array
  101414. {
  101415. if (null === $this->types) {
  101416. $typeExpression = $this->getTypeExpression();
  101417. $this->types = null === $typeExpression
  101418. ? []
  101419. : $typeExpression->getTypes();
  101420. }
  101421. return $this->types;
  101422. }
  101423. public function setTypes(array $types): void
  101424. {
  101425. $origTypesContent = $this->getTypesContent();
  101426. $newTypesContent = implode(
  101427. $this->getTypeExpression()->getTypesGlue() ?? '|',
  101428. $types
  101429. );
  101430. if ($origTypesContent === $newTypesContent) {
  101431. return;
  101432. }
  101433. $pattern = '/'.preg_quote($origTypesContent, '/').'/';
  101434. $this->lines[0]->setContent(Preg::replace($pattern, $newTypesContent, $this->lines[0]->getContent(), 1));
  101435. $this->clearCache();
  101436. }
  101437. public function getNormalizedTypes(): array
  101438. {
  101439. $typeExpression = $this->getTypeExpression();
  101440. if (null === $typeExpression) {
  101441. return [];
  101442. }
  101443. $normalizedTypeExpression = $typeExpression
  101444. ->mapTypes(static fn (TypeExpression $v) => new TypeExpression(strtolower($v->toString()), null, []))
  101445. ->sortTypes(static fn (TypeExpression $a, TypeExpression $b) => $a->toString() <=> $b->toString())
  101446. ;
  101447. return $normalizedTypeExpression->getTypes();
  101448. }
  101449. public function remove(): void
  101450. {
  101451. foreach ($this->lines as $line) {
  101452. if ($line->isTheStart() && $line->isTheEnd()) {
  101453. $line->remove();
  101454. } elseif ($line->isTheStart()) {
  101455. $content = Preg::replace('#(\s*/\*\*).*#', '$1', $line->getContent());
  101456. $line->setContent($content);
  101457. } elseif ($line->isTheEnd()) {
  101458. $content = Preg::replace('#(\s*)\S.*(\*/.*)#', '$1$2', $line->getContent());
  101459. $line->setContent($content);
  101460. } else {
  101461. $line->remove();
  101462. }
  101463. }
  101464. $this->clearCache();
  101465. }
  101466. public function getContent(): string
  101467. {
  101468. return implode('', $this->lines);
  101469. }
  101470. public function supportTypes(): bool
  101471. {
  101472. return \in_array($this->getTag()->getName(), self::TAGS, true);
  101473. }
  101474. private function getTypesContent(): ?string
  101475. {
  101476. if (null === $this->typesContent) {
  101477. $name = $this->getTag()->getName();
  101478. if (!$this->supportTypes()) {
  101479. throw new \RuntimeException('This tag does not support types.');
  101480. }
  101481. $matchingResult = Preg::match(
  101482. '{^(?:\h*\*|/\*\*)[\h*]*@'.$name.'\h+'.TypeExpression::REGEX_TYPES.'(?:(?:[*\h\v]|\&?[\.\$\s]).*)?\r?$}is',
  101483. $this->lines[0]->getContent(),
  101484. $matches
  101485. );
  101486. $this->typesContent = $matchingResult
  101487. ? $matches['types']
  101488. : null;
  101489. }
  101490. return $this->typesContent;
  101491. }
  101492. private function clearCache(): void
  101493. {
  101494. $this->types = null;
  101495. $this->typesContent = null;
  101496. }
  101497. }
  101498. <?php
  101499. declare(strict_types=1);
  101500. namespace PhpCsFixer\DocBlock;
  101501. use PhpCsFixer\Preg;
  101502. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  101503. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  101504. use PhpCsFixer\Utils;
  101505. final class TypeExpression
  101506. {
  101507. public const REGEX_IDENTIFIER = '(?:(?!(?<!\*)\d)[^\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]++)';
  101508. public const REGEX_TYPES = '(?<types>(?x) # one or several types separated by `|` or `&`
  101509. '.self::REGEX_TYPE.'
  101510. (?:
  101511. \h*(?<glue>[|&])\h*
  101512. (?&type)
  101513. )*+
  101514. )';
  101515. private const REGEX_TYPE = '(?<type>(?x) # single type
  101516. (?<nullable>\??\h*)
  101517. (?:
  101518. (?<array_shape>
  101519. (?<array_shape_name>(?i)(?:array|list|object)(?-i))
  101520. (?<array_shape_start>\h*\{\h*)
  101521. (?<array_shape_inners>
  101522. (?<array_shape_inner>
  101523. (?<array_shape_inner_key>(?:(?&constant)|(?&identifier)|(?&name))\h*\??\h*:\h*|)
  101524. (?<array_shape_inner_value>(?&types_inner))
  101525. )
  101526. (?:
  101527. \h*,\h*
  101528. (?&array_shape_inner)
  101529. )*+
  101530. (?:\h*,|(?!(?&array_shape_unsealed_variadic)))
  101531. |)
  101532. (?<array_shape_unsealed> # unsealed array shape, e.g. `...`. `...<string>`
  101533. (?<array_shape_unsealed_variadic>\h*\.\.\.)
  101534. (?<array_shape_unsealed_type>
  101535. (?<array_shape_unsealed_type_start>\h*<\h*)
  101536. (?<array_shape_unsealed_type_a>(?&types_inner))
  101537. (?:
  101538. (?<array_shape_unsealed_type_comma>\h*,\h*)
  101539. (?<array_shape_unsealed_type_b>(?&array_shape_unsealed_type_a))
  101540. |)
  101541. \h*>
  101542. |)
  101543. |)
  101544. \h*\}
  101545. )
  101546. |
  101547. (?<callable> # callable syntax, e.g. `callable(string, int...): bool`, `\Closure<T>(T, int): T`
  101548. (?<callable_name>(?&name))
  101549. (?<callable_template>
  101550. (?<callable_template_start>\h*<\h*)
  101551. (?<callable_template_inners>
  101552. (?<callable_template_inner>
  101553. (?<callable_template_inner_name>
  101554. (?&identifier)
  101555. )
  101556. (?<callable_template_inner_b> # template bound
  101557. \h+(?i)(?<callable_template_inner_b_kw>of|as)(?-i)\h+
  101558. (?<callable_template_inner_b_types>(?&types_inner))
  101559. |)
  101560. (?<callable_template_inner_d> # template default
  101561. \h*=\h*
  101562. (?<callable_template_inner_d_types>(?&types_inner))
  101563. |)
  101564. )
  101565. (?:
  101566. \h*,\h*
  101567. (?&callable_template_inner)
  101568. )*+
  101569. )
  101570. \h*>
  101571. (?=\h*\()
  101572. |)
  101573. (?<callable_start>\h*\(\h*)
  101574. (?<callable_arguments>
  101575. (?<callable_argument>
  101576. (?<callable_argument_type>(?&types_inner))
  101577. (?<callable_argument_is_reference>\h*&|)
  101578. (?<callable_argument_is_variadic>\h*\.\.\.|)
  101579. (?<callable_argument_name>\h*\$(?&identifier)|)
  101580. (?<callable_argument_is_optional>\h*=|)
  101581. )
  101582. (?:
  101583. \h*,\h*
  101584. (?&callable_argument)
  101585. )*+
  101586. (?:\h*,)?
  101587. |)
  101588. \h*\)
  101589. (?:
  101590. \h*\:\h*
  101591. (?<callable_return>(?&type))
  101592. )?
  101593. )
  101594. |
  101595. (?<generic> # generic syntax, e.g.: `array<int, \Foo\Bar>`
  101596. (?<generic_name>(?&name))
  101597. (?<generic_start>\h*<\h*)
  101598. (?<generic_types>
  101599. (?&types_inner)
  101600. (?:
  101601. \h*,\h*
  101602. (?&types_inner)
  101603. )*+
  101604. (?:\h*,)?
  101605. )
  101606. \h*>
  101607. )
  101608. |
  101609. (?<class_constant> # class constants with optional wildcard, e.g.: `Foo::*`, `Foo::CONST_A`, `FOO::CONST_*`
  101610. (?<class_constant_name>(?&name))
  101611. ::\*?(?:(?&identifier)\*?)*
  101612. )
  101613. |
  101614. (?<constant> # single constant value (case insensitive), e.g.: 1, -1.8E+6, `\'a\'`
  101615. (?i)
  101616. # all sorts of numbers: with or without sign, supports literal separator and several numeric systems,
  101617. # e.g.: 1, +1.1, 1., .1, -1, 123E+8, 123_456_789, 0x7Fb4, 0b0110, 0o777
  101618. [+-]?(?:
  101619. (?:0b[01]++(?:_[01]++)*+)
  101620. | (?:0o[0-7]++(?:_[0-7]++)*+)
  101621. | (?:0x[\da-f]++(?:_[\da-f]++)*+)
  101622. | (?:(?<constant_digits>\d++(?:_\d++)*+)|(?=\.\d))
  101623. (?:\.(?&constant_digits)|(?<=\d)\.)?+
  101624. (?:e[+-]?(?&constant_digits))?+
  101625. )
  101626. | \'(?:[^\'\\\]|\\\.)*+\'
  101627. | "(?:[^"\\\]|\\\.)*+"
  101628. (?-i)
  101629. )
  101630. |
  101631. (?<this> # self reference, e.g.: $this, $self, @static
  101632. (?i)
  101633. [@$](?:this | self | static)
  101634. (?-i)
  101635. )
  101636. |
  101637. (?<name> # full name, e.g.: `int`, `\DateTime`, `\Foo\Bar`, `positive-int`
  101638. \\\?+
  101639. (?<identifier>'.self::REGEX_IDENTIFIER.')
  101640. (?:[\\\\\-](?&identifier))*+
  101641. )
  101642. |
  101643. (?<parenthesized> # parenthesized type, e.g.: `(int)`, `(int|\stdClass)`
  101644. (?<parenthesized_start>
  101645. \(\h*
  101646. )
  101647. (?:
  101648. (?<parenthesized_types>
  101649. (?&types_inner)
  101650. )
  101651. |
  101652. (?<conditional> # conditional type, e.g.: `$foo is \Throwable ? false : $foo`
  101653. (?<conditional_cond_left>
  101654. (?:\$(?&identifier))
  101655. |
  101656. (?<conditional_cond_left_types>(?&types_inner))
  101657. )
  101658. (?<conditional_cond_middle>
  101659. \h+(?i)is(?:\h+not)?(?-i)\h+
  101660. )
  101661. (?<conditional_cond_right_types>(?&types_inner))
  101662. (?<conditional_true_start>\h*\?\h*)
  101663. (?<conditional_true_types>(?&types_inner))
  101664. (?<conditional_false_start>\h*:\h*)
  101665. (?<conditional_false_types>(?&types_inner))
  101666. )
  101667. )
  101668. \h*\)
  101669. )
  101670. )
  101671. (?<array> # array, e.g.: `string[]`, `array<int, string>[][]`
  101672. (\h*\[\h*\])*
  101673. )
  101674. (?:(?=1)0
  101675. (?<types_inner>(?>
  101676. (?&type)
  101677. (?:
  101678. \h*[|&]\h*
  101679. (?&type)
  101680. )*+
  101681. ))
  101682. |)
  101683. )';
  101684. private string $value;
  101685. private bool $isCompositeType;
  101686. private ?string $typesGlue = null;
  101687. private array $innerTypeExpressions = [];
  101688. private ?NamespaceAnalysis $namespace;
  101689. private array $namespaceUses;
  101690. public function __construct(string $value, ?NamespaceAnalysis $namespace, array $namespaceUses)
  101691. {
  101692. $this->value = $value;
  101693. $this->namespace = $namespace;
  101694. $this->namespaceUses = $namespaceUses;
  101695. $this->parse();
  101696. }
  101697. public function toString(): string
  101698. {
  101699. return $this->value;
  101700. }
  101701. public function getTypes(): array
  101702. {
  101703. if ($this->isCompositeType) {
  101704. return array_map(
  101705. static fn (array $type) => $type['expression']->toString(),
  101706. $this->innerTypeExpressions,
  101707. );
  101708. }
  101709. return [$this->value];
  101710. }
  101711. public function isCompositeType(): bool
  101712. {
  101713. return $this->isCompositeType;
  101714. }
  101715. public function isUnionType(): bool
  101716. {
  101717. return $this->isCompositeType && '|' === $this->typesGlue;
  101718. }
  101719. public function isIntersectionType(): bool
  101720. {
  101721. return $this->isCompositeType && '&' === $this->typesGlue;
  101722. }
  101723. public function getTypesGlue(): ?string
  101724. {
  101725. return $this->typesGlue;
  101726. }
  101727. public function mapTypes(\Closure $callback): self
  101728. {
  101729. $value = $this->value;
  101730. $startIndexOffset = 0;
  101731. foreach ($this->innerTypeExpressions as [
  101732. 'start_index' => $startIndexOrig,
  101733. 'expression' => $inner,
  101734. ]) {
  101735. $innerValueOrig = $inner->value;
  101736. $inner = $inner->mapTypes($callback);
  101737. if ($inner->value !== $innerValueOrig) {
  101738. $value = substr_replace(
  101739. $value,
  101740. $inner->value,
  101741. $startIndexOrig + $startIndexOffset,
  101742. \strlen($innerValueOrig)
  101743. );
  101744. $startIndexOffset += \strlen($inner->value) - \strlen($innerValueOrig);
  101745. }
  101746. }
  101747. $type = $value === $this->value
  101748. ? $this
  101749. : $this->inner($value);
  101750. return $callback($type);
  101751. }
  101752. public function walkTypes(\Closure $callback): void
  101753. {
  101754. $this->mapTypes(static function (self $type) use ($callback) {
  101755. $valueOrig = $type->value;
  101756. $callback($type);
  101757. \assert($type->value === $valueOrig);
  101758. return $type;
  101759. });
  101760. }
  101761. public function sortTypes(\Closure $compareCallback): self
  101762. {
  101763. return $this->mapTypes(function (self $type) use ($compareCallback): self {
  101764. if ($type->isCompositeType) {
  101765. $innerTypeExpressions = Utils::stableSort(
  101766. $type->innerTypeExpressions,
  101767. static fn (array $v): self => $v['expression'],
  101768. $compareCallback,
  101769. );
  101770. if ($innerTypeExpressions !== $type->innerTypeExpressions) {
  101771. $value = implode(
  101772. $type->getTypesGlue(),
  101773. array_map(static fn (array $v): string => $v['expression']->toString(), $innerTypeExpressions)
  101774. );
  101775. return $this->inner($value);
  101776. }
  101777. }
  101778. return $type;
  101779. });
  101780. }
  101781. public function getCommonType(): ?string
  101782. {
  101783. $aliases = $this->getAliases();
  101784. $mainType = null;
  101785. foreach ($this->getTypes() as $type) {
  101786. if ('null' === $type) {
  101787. continue;
  101788. }
  101789. if (str_starts_with($type, '?')) {
  101790. $type = substr($type, 1);
  101791. }
  101792. if (Preg::match('/\[\h*\]$/', $type)) {
  101793. $type = 'array';
  101794. } elseif (Preg::match('/^(.+?)\h*[<{(]/', $type, $matches)) {
  101795. $type = $matches[1];
  101796. }
  101797. if (isset($aliases[$type])) {
  101798. $type = $aliases[$type];
  101799. }
  101800. if (null === $mainType || $type === $mainType) {
  101801. $mainType = $type;
  101802. continue;
  101803. }
  101804. $mainType = $this->getParentType($type, $mainType);
  101805. if (null === $mainType) {
  101806. return null;
  101807. }
  101808. }
  101809. return $mainType;
  101810. }
  101811. public function allowsNull(): bool
  101812. {
  101813. foreach ($this->getTypes() as $type) {
  101814. if (\in_array($type, ['null', 'mixed'], true) || str_starts_with($type, '?')) {
  101815. return true;
  101816. }
  101817. }
  101818. return false;
  101819. }
  101820. private function parse(): void
  101821. {
  101822. $seenGlues = null;
  101823. $innerValues = [];
  101824. $index = 0;
  101825. while (true) {
  101826. Preg::match(
  101827. '{\G'.self::REGEX_TYPE.'(?<glue_raw>\h*(?<glue>[|&])\h*(?!$)|$)}',
  101828. $this->value,
  101829. $matches,
  101830. PREG_OFFSET_CAPTURE,
  101831. $index
  101832. );
  101833. if ([] === $matches) {
  101834. throw new \Exception('Unable to parse phpdoc type '.var_export($this->value, true));
  101835. }
  101836. if (null === $seenGlues) {
  101837. if (($matches['glue'][0] ?? '') === '') {
  101838. break;
  101839. }
  101840. $seenGlues = ['|' => false, '&' => false];
  101841. }
  101842. if (($matches['glue'][0] ?? '') !== '') {
  101843. \assert(isset($seenGlues[$matches['glue'][0]]));
  101844. $seenGlues[$matches['glue'][0]] = true;
  101845. }
  101846. $innerValues[] = [
  101847. 'start_index' => $index,
  101848. 'value' => $matches['type'][0],
  101849. 'next_glue' => $matches['glue'][0] ?? null,
  101850. 'next_glue_raw' => $matches['glue_raw'][0] ?? null,
  101851. ];
  101852. $consumedValueLength = \strlen($matches[0][0]);
  101853. $index += $consumedValueLength;
  101854. if (\strlen($this->value) <= $index) {
  101855. \assert(\strlen($this->value) === $index);
  101856. $seenGlues = array_filter($seenGlues);
  101857. \assert([] !== $seenGlues);
  101858. $this->isCompositeType = true;
  101859. $this->typesGlue = array_key_first($seenGlues);
  101860. if (1 === \count($seenGlues)) {
  101861. foreach ($innerValues as $innerValue) {
  101862. $this->innerTypeExpressions[] = [
  101863. 'start_index' => $innerValue['start_index'],
  101864. 'expression' => $this->inner($innerValue['value']),
  101865. ];
  101866. }
  101867. } else {
  101868. for ($i = 0; $i < \count($innerValues); ++$i) {
  101869. $innerStartIndex = $innerValues[$i]['start_index'];
  101870. $innerValue = '';
  101871. while (true) {
  101872. $innerValue .= $innerValues[$i]['value'];
  101873. if (($innerValues[$i]['next_glue'] ?? $this->typesGlue) === $this->typesGlue) {
  101874. break;
  101875. }
  101876. $innerValue .= $innerValues[$i]['next_glue_raw'];
  101877. ++$i;
  101878. }
  101879. $this->innerTypeExpressions[] = [
  101880. 'start_index' => $innerStartIndex,
  101881. 'expression' => $this->inner($innerValue),
  101882. ];
  101883. }
  101884. }
  101885. return;
  101886. }
  101887. }
  101888. $this->isCompositeType = false;
  101889. if ('' !== $matches['nullable'][0]) {
  101890. $this->innerTypeExpressions[] = [
  101891. 'start_index' => \strlen($matches['nullable'][0]),
  101892. 'expression' => $this->inner(substr($matches['type'][0], \strlen($matches['nullable'][0]))),
  101893. ];
  101894. } elseif ('' !== $matches['array'][0]) {
  101895. $this->innerTypeExpressions[] = [
  101896. 'start_index' => 0,
  101897. 'expression' => $this->inner(substr($matches['type'][0], 0, -\strlen($matches['array'][0]))),
  101898. ];
  101899. } elseif ('' !== ($matches['generic'][0] ?? '') && 0 === $matches['generic'][1]) {
  101900. $this->innerTypeExpressions[] = [
  101901. 'start_index' => 0,
  101902. 'expression' => $this->inner($matches['generic_name'][0]),
  101903. ];
  101904. $this->parseCommaSeparatedInnerTypes(
  101905. \strlen($matches['generic_name'][0]) + \strlen($matches['generic_start'][0]),
  101906. $matches['generic_types'][0]
  101907. );
  101908. } elseif ('' !== ($matches['callable'][0] ?? '') && 0 === $matches['callable'][1]) {
  101909. $this->innerTypeExpressions[] = [
  101910. 'start_index' => 0,
  101911. 'expression' => $this->inner($matches['callable_name'][0]),
  101912. ];
  101913. $this->parseCallableTemplateInnerTypes(
  101914. \strlen($matches['callable_name'][0])
  101915. + \strlen($matches['callable_template_start'][0]),
  101916. $matches['callable_template_inners'][0]
  101917. );
  101918. $this->parseCallableArgumentTypes(
  101919. \strlen($matches['callable_name'][0])
  101920. + \strlen($matches['callable_template'][0])
  101921. + \strlen($matches['callable_start'][0]),
  101922. $matches['callable_arguments'][0]
  101923. );
  101924. if ('' !== ($matches['callable_return'][0] ?? '')) {
  101925. $this->innerTypeExpressions[] = [
  101926. 'start_index' => \strlen($this->value) - \strlen($matches['callable_return'][0]),
  101927. 'expression' => $this->inner($matches['callable_return'][0]),
  101928. ];
  101929. }
  101930. } elseif ('' !== ($matches['array_shape'][0] ?? '') && 0 === $matches['array_shape'][1]) {
  101931. $this->innerTypeExpressions[] = [
  101932. 'start_index' => 0,
  101933. 'expression' => $this->inner($matches['array_shape_name'][0]),
  101934. ];
  101935. $nextIndex = \strlen($matches['array_shape_name'][0]) + \strlen($matches['array_shape_start'][0]);
  101936. $this->parseArrayShapeInnerTypes(
  101937. $nextIndex,
  101938. $matches['array_shape_inners'][0]
  101939. );
  101940. if ('' !== ($matches['array_shape_unsealed_type'][0] ?? '')) {
  101941. $nextIndex += \strlen($matches['array_shape_inners'][0])
  101942. + \strlen($matches['array_shape_unsealed_variadic'][0])
  101943. + \strlen($matches['array_shape_unsealed_type_start'][0]);
  101944. $this->innerTypeExpressions[] = [
  101945. 'start_index' => $nextIndex,
  101946. 'expression' => $this->inner($matches['array_shape_unsealed_type_a'][0]),
  101947. ];
  101948. if ('' !== ($matches['array_shape_unsealed_type_b'][0] ?? '')) {
  101949. $nextIndex += \strlen($matches['array_shape_unsealed_type_a'][0])
  101950. + \strlen($matches['array_shape_unsealed_type_comma'][0]);
  101951. $this->innerTypeExpressions[] = [
  101952. 'start_index' => $nextIndex,
  101953. 'expression' => $this->inner($matches['array_shape_unsealed_type_b'][0]),
  101954. ];
  101955. }
  101956. }
  101957. } elseif ('' !== ($matches['parenthesized'][0] ?? '') && 0 === $matches['parenthesized'][1]) {
  101958. $index = \strlen($matches['parenthesized_start'][0]);
  101959. if ('' !== ($matches['conditional'][0] ?? '')) {
  101960. if ('' !== ($matches['conditional_cond_left_types'][0] ?? '')) {
  101961. $this->innerTypeExpressions[] = [
  101962. 'start_index' => $index,
  101963. 'expression' => $this->inner($matches['conditional_cond_left_types'][0]),
  101964. ];
  101965. }
  101966. $index += \strlen($matches['conditional_cond_left'][0]) + \strlen($matches['conditional_cond_middle'][0]);
  101967. $this->innerTypeExpressions[] = [
  101968. 'start_index' => $index,
  101969. 'expression' => $this->inner($matches['conditional_cond_right_types'][0]),
  101970. ];
  101971. $index += \strlen($matches['conditional_cond_right_types'][0]) + \strlen($matches['conditional_true_start'][0]);
  101972. $this->innerTypeExpressions[] = [
  101973. 'start_index' => $index,
  101974. 'expression' => $this->inner($matches['conditional_true_types'][0]),
  101975. ];
  101976. $index += \strlen($matches['conditional_true_types'][0]) + \strlen($matches['conditional_false_start'][0]);
  101977. $this->innerTypeExpressions[] = [
  101978. 'start_index' => $index,
  101979. 'expression' => $this->inner($matches['conditional_false_types'][0]),
  101980. ];
  101981. } else {
  101982. $this->innerTypeExpressions[] = [
  101983. 'start_index' => $index,
  101984. 'expression' => $this->inner($matches['parenthesized_types'][0]),
  101985. ];
  101986. }
  101987. } elseif ('' !== $matches['class_constant'][0]) {
  101988. $this->innerTypeExpressions[] = [
  101989. 'start_index' => 0,
  101990. 'expression' => $this->inner($matches['class_constant_name'][0]),
  101991. ];
  101992. }
  101993. }
  101994. private function parseCommaSeparatedInnerTypes(int $startIndex, string $value): void
  101995. {
  101996. $index = 0;
  101997. while (\strlen($value) !== $index) {
  101998. Preg::match(
  101999. '{\G'.self::REGEX_TYPES.'(?:\h*,\h*|$)}',
  102000. $value,
  102001. $matches,
  102002. 0,
  102003. $index
  102004. );
  102005. $this->innerTypeExpressions[] = [
  102006. 'start_index' => $startIndex + $index,
  102007. 'expression' => $this->inner($matches['types']),
  102008. ];
  102009. $index += \strlen($matches[0]);
  102010. }
  102011. }
  102012. private function parseCallableTemplateInnerTypes(int $startIndex, string $value): void
  102013. {
  102014. $index = 0;
  102015. while (\strlen($value) !== $index) {
  102016. Preg::match(
  102017. '{\G(?:(?=1)0'.self::REGEX_TYPES.'|(?<_callable_template_inner>(?&callable_template_inner))(?:\h*,\h*|$))}',
  102018. $value,
  102019. $prematches,
  102020. 0,
  102021. $index
  102022. );
  102023. $consumedValue = $prematches['_callable_template_inner'];
  102024. $consumedValueLength = \strlen($consumedValue);
  102025. $consumedCommaLength = \strlen($prematches[0]) - $consumedValueLength;
  102026. $addedPrefix = 'Closure<';
  102027. Preg::match(
  102028. '{^'.self::REGEX_TYPES.'$}',
  102029. $addedPrefix.$consumedValue.'>(): void',
  102030. $matches,
  102031. PREG_OFFSET_CAPTURE
  102032. );
  102033. if ('' !== $matches['callable_template_inner_b'][0]) {
  102034. $this->innerTypeExpressions[] = [
  102035. 'start_index' => $startIndex + $index + $matches['callable_template_inner_b_types'][1]
  102036. - \strlen($addedPrefix),
  102037. 'expression' => $this->inner($matches['callable_template_inner_b_types'][0]),
  102038. ];
  102039. }
  102040. if ('' !== $matches['callable_template_inner_d'][0]) {
  102041. $this->innerTypeExpressions[] = [
  102042. 'start_index' => $startIndex + $index + $matches['callable_template_inner_d_types'][1]
  102043. - \strlen($addedPrefix),
  102044. 'expression' => $this->inner($matches['callable_template_inner_d_types'][0]),
  102045. ];
  102046. }
  102047. $index += $consumedValueLength + $consumedCommaLength;
  102048. }
  102049. }
  102050. private function parseCallableArgumentTypes(int $startIndex, string $value): void
  102051. {
  102052. $index = 0;
  102053. while (\strlen($value) !== $index) {
  102054. Preg::match(
  102055. '{\G(?:(?=1)0'.self::REGEX_TYPES.'|(?<_callable_argument>(?&callable_argument))(?:\h*,\h*|$))}',
  102056. $value,
  102057. $prematches,
  102058. 0,
  102059. $index
  102060. );
  102061. $consumedValue = $prematches['_callable_argument'];
  102062. $consumedValueLength = \strlen($consumedValue);
  102063. $consumedCommaLength = \strlen($prematches[0]) - $consumedValueLength;
  102064. $addedPrefix = 'Closure(';
  102065. Preg::match(
  102066. '{^'.self::REGEX_TYPES.'$}',
  102067. $addedPrefix.$consumedValue.'): void',
  102068. $matches,
  102069. PREG_OFFSET_CAPTURE
  102070. );
  102071. $this->innerTypeExpressions[] = [
  102072. 'start_index' => $startIndex + $index,
  102073. 'expression' => $this->inner($matches['callable_argument_type'][0]),
  102074. ];
  102075. $index += $consumedValueLength + $consumedCommaLength;
  102076. }
  102077. }
  102078. private function parseArrayShapeInnerTypes(int $startIndex, string $value): void
  102079. {
  102080. $index = 0;
  102081. while (\strlen($value) !== $index) {
  102082. Preg::match(
  102083. '{\G(?:(?=1)0'.self::REGEX_TYPES.'|(?<_array_shape_inner>(?&array_shape_inner))(?:\h*,\h*|$))}',
  102084. $value,
  102085. $prematches,
  102086. 0,
  102087. $index
  102088. );
  102089. $consumedValue = $prematches['_array_shape_inner'];
  102090. $consumedValueLength = \strlen($consumedValue);
  102091. $consumedCommaLength = \strlen($prematches[0]) - $consumedValueLength;
  102092. $addedPrefix = 'array{';
  102093. Preg::match(
  102094. '{^'.self::REGEX_TYPES.'$}',
  102095. $addedPrefix.$consumedValue.'}',
  102096. $matches,
  102097. PREG_OFFSET_CAPTURE
  102098. );
  102099. $this->innerTypeExpressions[] = [
  102100. 'start_index' => $startIndex + $index + $matches['array_shape_inner_value'][1]
  102101. - \strlen($addedPrefix),
  102102. 'expression' => $this->inner($matches['array_shape_inner_value'][0]),
  102103. ];
  102104. $index += $consumedValueLength + $consumedCommaLength;
  102105. }
  102106. }
  102107. private function inner(string $value): self
  102108. {
  102109. return new self($value, $this->namespace, $this->namespaceUses);
  102110. }
  102111. private function getParentType(string $type1, string $type2): ?string
  102112. {
  102113. $types = [
  102114. $this->normalize($type1),
  102115. $this->normalize($type2),
  102116. ];
  102117. natcasesort($types);
  102118. $types = implode('|', $types);
  102119. $parents = [
  102120. 'array|Traversable' => 'iterable',
  102121. 'array|iterable' => 'iterable',
  102122. 'iterable|Traversable' => 'iterable',
  102123. 'self|static' => 'self',
  102124. ];
  102125. return $parents[$types] ?? null;
  102126. }
  102127. private function normalize(string $type): string
  102128. {
  102129. $aliases = $this->getAliases();
  102130. if (isset($aliases[$type])) {
  102131. return $aliases[$type];
  102132. }
  102133. if (\in_array($type, [
  102134. 'array',
  102135. 'bool',
  102136. 'callable',
  102137. 'false',
  102138. 'float',
  102139. 'int',
  102140. 'iterable',
  102141. 'mixed',
  102142. 'never',
  102143. 'null',
  102144. 'object',
  102145. 'resource',
  102146. 'string',
  102147. 'true',
  102148. 'void',
  102149. ], true)) {
  102150. return $type;
  102151. }
  102152. if (Preg::match('/\[\]$/', $type)) {
  102153. return 'array';
  102154. }
  102155. if (Preg::match('/^(.+?)</', $type, $matches)) {
  102156. return $matches[1];
  102157. }
  102158. if (str_starts_with($type, '\\')) {
  102159. return substr($type, 1);
  102160. }
  102161. foreach ($this->namespaceUses as $namespaceUse) {
  102162. if ($namespaceUse->getShortName() === $type) {
  102163. return $namespaceUse->getFullName();
  102164. }
  102165. }
  102166. if (null === $this->namespace || $this->namespace->isGlobalNamespace()) {
  102167. return $type;
  102168. }
  102169. return "{$this->namespace->getFullName()}\\{$type}";
  102170. }
  102171. private function getAliases(): array
  102172. {
  102173. return [
  102174. 'boolean' => 'bool',
  102175. 'callback' => 'callable',
  102176. 'double' => 'float',
  102177. 'false' => 'bool',
  102178. 'integer' => 'int',
  102179. 'list' => 'array',
  102180. 'real' => 'float',
  102181. 'true' => 'bool',
  102182. ];
  102183. }
  102184. }
  102185. <?php
  102186. declare(strict_types=1);
  102187. namespace PhpCsFixer\DocBlock;
  102188. /**
  102189. @readonly
  102190. */
  102191. final class ShortDescription
  102192. {
  102193. private DocBlock $doc;
  102194. public function __construct(DocBlock $doc)
  102195. {
  102196. $this->doc = $doc;
  102197. }
  102198. public function getEnd(): ?int
  102199. {
  102200. $reachedContent = false;
  102201. foreach ($this->doc->getLines() as $index => $line) {
  102202. if ($reachedContent && ($line->containsATag() || !$line->containsUsefulContent())) {
  102203. return $index - 1;
  102204. }
  102205. if ($line->containsATag()) {
  102206. return null;
  102207. }
  102208. if ($line->containsUsefulContent()) {
  102209. $reachedContent = true;
  102210. }
  102211. }
  102212. return null;
  102213. }
  102214. }
  102215. <?php
  102216. declare(strict_types=1);
  102217. namespace PhpCsFixer\DocBlock;
  102218. use PhpCsFixer\Preg;
  102219. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  102220. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  102221. final class DocBlock
  102222. {
  102223. private array $lines = [];
  102224. private ?array $annotations = null;
  102225. private ?NamespaceAnalysis $namespace;
  102226. private array $namespaceUses;
  102227. public function __construct(string $content, ?NamespaceAnalysis $namespace = null, array $namespaceUses = [])
  102228. {
  102229. foreach (Preg::split('/([^\n\r]+\R*)/', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $line) {
  102230. $this->lines[] = new Line($line);
  102231. }
  102232. $this->namespace = $namespace;
  102233. $this->namespaceUses = $namespaceUses;
  102234. }
  102235. public function __toString(): string
  102236. {
  102237. return $this->getContent();
  102238. }
  102239. public function getLines(): array
  102240. {
  102241. return $this->lines;
  102242. }
  102243. public function getLine(int $pos): ?Line
  102244. {
  102245. return $this->lines[$pos] ?? null;
  102246. }
  102247. public function getAnnotations(): array
  102248. {
  102249. if (null !== $this->annotations) {
  102250. return $this->annotations;
  102251. }
  102252. $this->annotations = [];
  102253. $total = \count($this->lines);
  102254. for ($index = 0; $index < $total; ++$index) {
  102255. if ($this->lines[$index]->containsATag()) {
  102256. $lines = \array_slice($this->lines, $index, $this->findAnnotationLength($index), true);
  102257. $annotation = new Annotation($lines, $this->namespace, $this->namespaceUses);
  102258. $index = $annotation->getEnd();
  102259. $this->annotations[] = $annotation;
  102260. }
  102261. }
  102262. return $this->annotations;
  102263. }
  102264. public function isMultiLine(): bool
  102265. {
  102266. return 1 !== \count($this->lines);
  102267. }
  102268. public function makeMultiLine(string $indent, string $lineEnd): void
  102269. {
  102270. if ($this->isMultiLine()) {
  102271. return;
  102272. }
  102273. $lineContent = $this->getSingleLineDocBlockEntry($this->lines[0]);
  102274. if ('' === $lineContent) {
  102275. $this->lines = [
  102276. new Line('/**'.$lineEnd),
  102277. new Line($indent.' *'.$lineEnd),
  102278. new Line($indent.' */'),
  102279. ];
  102280. return;
  102281. }
  102282. $this->lines = [
  102283. new Line('/**'.$lineEnd),
  102284. new Line($indent.' * '.$lineContent.$lineEnd),
  102285. new Line($indent.' */'),
  102286. ];
  102287. }
  102288. public function makeSingleLine(): void
  102289. {
  102290. if (!$this->isMultiLine()) {
  102291. return;
  102292. }
  102293. $usefulLines = array_filter(
  102294. $this->lines,
  102295. static fn (Line $line): bool => $line->containsUsefulContent()
  102296. );
  102297. if (1 < \count($usefulLines)) {
  102298. return;
  102299. }
  102300. $lineContent = '';
  102301. if (\count($usefulLines) > 0) {
  102302. $lineContent = $this->getSingleLineDocBlockEntry(array_shift($usefulLines));
  102303. }
  102304. $this->lines = [new Line('/** '.$lineContent.' */')];
  102305. }
  102306. public function getAnnotation(int $pos): ?Annotation
  102307. {
  102308. $annotations = $this->getAnnotations();
  102309. return $annotations[$pos] ?? null;
  102310. }
  102311. public function getAnnotationsOfType($types): array
  102312. {
  102313. $typesToSearchFor = (array) $types;
  102314. $annotations = [];
  102315. foreach ($this->getAnnotations() as $annotation) {
  102316. $tagName = $annotation->getTag()->getName();
  102317. if (\in_array($tagName, $typesToSearchFor, true)) {
  102318. $annotations[] = $annotation;
  102319. }
  102320. }
  102321. return $annotations;
  102322. }
  102323. public function getContent(): string
  102324. {
  102325. return implode('', $this->lines);
  102326. }
  102327. private function findAnnotationLength(int $start): int
  102328. {
  102329. $index = $start;
  102330. while (($line = $this->getLine(++$index)) !== null) {
  102331. if ($line->containsATag()) {
  102332. break;
  102333. }
  102334. if (!$line->containsUsefulContent()) {
  102335. $next = $this->getLine($index + 1);
  102336. if (null === $next || !$next->containsUsefulContent() || $next->containsATag()) {
  102337. break;
  102338. }
  102339. }
  102340. }
  102341. return $index - $start;
  102342. }
  102343. private function getSingleLineDocBlockEntry(Line $line): string
  102344. {
  102345. $lineString = $line->getContent();
  102346. if ('' === $lineString) {
  102347. return $lineString;
  102348. }
  102349. $lineString = str_replace('*/', '', $lineString);
  102350. $lineString = trim($lineString);
  102351. if (str_starts_with($lineString, '/**')) {
  102352. $lineString = substr($lineString, 3);
  102353. } elseif (str_starts_with($lineString, '*')) {
  102354. $lineString = substr($lineString, 1);
  102355. }
  102356. return trim($lineString);
  102357. }
  102358. }
  102359. <?php
  102360. declare(strict_types=1);
  102361. namespace PhpCsFixer\DocBlock;
  102362. use PhpCsFixer\Preg;
  102363. final class Line
  102364. {
  102365. private string $content;
  102366. public function __construct(string $content)
  102367. {
  102368. $this->content = $content;
  102369. }
  102370. public function __toString(): string
  102371. {
  102372. return $this->content;
  102373. }
  102374. public function getContent(): string
  102375. {
  102376. return $this->content;
  102377. }
  102378. public function containsUsefulContent(): bool
  102379. {
  102380. return Preg::match('/\*\s*\S+/', $this->content) && '' !== trim(str_replace(['/', '*'], ' ', $this->content));
  102381. }
  102382. public function containsATag(): bool
  102383. {
  102384. return Preg::match('/\*\s*@/', $this->content);
  102385. }
  102386. public function isTheStart(): bool
  102387. {
  102388. return str_contains($this->content, '/**');
  102389. }
  102390. public function isTheEnd(): bool
  102391. {
  102392. return str_contains($this->content, '*/');
  102393. }
  102394. public function setContent(string $content): void
  102395. {
  102396. $this->content = $content;
  102397. }
  102398. public function remove(): void
  102399. {
  102400. $this->content = '';
  102401. }
  102402. public function addBlank(): void
  102403. {
  102404. $matched = Preg::match('/^(\h*\*)[^\r\n]*(\r?\n)$/', $this->content, $matches);
  102405. if (!$matched) {
  102406. return;
  102407. }
  102408. $this->content .= $matches[1].$matches[2];
  102409. }
  102410. }
  102411. <?php
  102412. declare(strict_types=1);
  102413. namespace PhpCsFixer\FixerDefinition;
  102414. /**
  102415. @readonly
  102416. */
  102417. final class CodeSample implements CodeSampleInterface
  102418. {
  102419. private string $code;
  102420. private ?array $configuration;
  102421. public function __construct(string $code, ?array $configuration = null)
  102422. {
  102423. $this->code = $code;
  102424. $this->configuration = $configuration;
  102425. }
  102426. public function getCode(): string
  102427. {
  102428. return $this->code;
  102429. }
  102430. public function getConfiguration(): ?array
  102431. {
  102432. return $this->configuration;
  102433. }
  102434. }
  102435. <?php
  102436. declare(strict_types=1);
  102437. namespace PhpCsFixer\FixerDefinition;
  102438. interface CodeSampleInterface
  102439. {
  102440. public function getCode(): string;
  102441. public function getConfiguration(): ?array;
  102442. }
  102443. <?php
  102444. declare(strict_types=1);
  102445. namespace PhpCsFixer\FixerDefinition;
  102446. interface VersionSpecificCodeSampleInterface extends CodeSampleInterface
  102447. {
  102448. public function isSuitableFor(int $version): bool;
  102449. }
  102450. <?php
  102451. declare(strict_types=1);
  102452. namespace PhpCsFixer\FixerDefinition;
  102453. /**
  102454. @readonly
  102455. */
  102456. final class FixerDefinition implements FixerDefinitionInterface
  102457. {
  102458. private string $summary;
  102459. private array $codeSamples;
  102460. private ?string $description;
  102461. private ?string $riskyDescription;
  102462. public function __construct(
  102463. string $summary,
  102464. array $codeSamples,
  102465. ?string $description = null,
  102466. ?string $riskyDescription = null
  102467. ) {
  102468. $this->summary = $summary;
  102469. $this->codeSamples = $codeSamples;
  102470. $this->description = $description;
  102471. $this->riskyDescription = $riskyDescription;
  102472. }
  102473. public function getSummary(): string
  102474. {
  102475. return $this->summary;
  102476. }
  102477. public function getDescription(): ?string
  102478. {
  102479. return $this->description;
  102480. }
  102481. public function getRiskyDescription(): ?string
  102482. {
  102483. return $this->riskyDescription;
  102484. }
  102485. public function getCodeSamples(): array
  102486. {
  102487. return $this->codeSamples;
  102488. }
  102489. }
  102490. <?php
  102491. declare(strict_types=1);
  102492. namespace PhpCsFixer\FixerDefinition;
  102493. /**
  102494. @readonly
  102495. */
  102496. final class FileSpecificCodeSample implements FileSpecificCodeSampleInterface
  102497. {
  102498. private CodeSampleInterface $codeSample;
  102499. private \SplFileInfo $splFileInfo;
  102500. public function __construct(
  102501. string $code,
  102502. \SplFileInfo $splFileInfo,
  102503. ?array $configuration = null
  102504. ) {
  102505. $this->codeSample = new CodeSample($code, $configuration);
  102506. $this->splFileInfo = $splFileInfo;
  102507. }
  102508. public function getCode(): string
  102509. {
  102510. return $this->codeSample->getCode();
  102511. }
  102512. public function getConfiguration(): ?array
  102513. {
  102514. return $this->codeSample->getConfiguration();
  102515. }
  102516. public function getSplFileInfo(): \SplFileInfo
  102517. {
  102518. return $this->splFileInfo;
  102519. }
  102520. }
  102521. <?php
  102522. declare(strict_types=1);
  102523. namespace PhpCsFixer\FixerDefinition;
  102524. interface VersionSpecificationInterface
  102525. {
  102526. public function isSatisfiedBy(int $version): bool;
  102527. }
  102528. <?php
  102529. declare(strict_types=1);
  102530. namespace PhpCsFixer\FixerDefinition;
  102531. interface FixerDefinitionInterface
  102532. {
  102533. public function getSummary(): string;
  102534. public function getDescription(): ?string;
  102535. public function getRiskyDescription(): ?string;
  102536. public function getCodeSamples(): array;
  102537. }
  102538. <?php
  102539. declare(strict_types=1);
  102540. namespace PhpCsFixer\FixerDefinition;
  102541. /**
  102542. @readonly
  102543. */
  102544. final class VersionSpecificCodeSample implements VersionSpecificCodeSampleInterface
  102545. {
  102546. private CodeSampleInterface $codeSample;
  102547. private VersionSpecificationInterface $versionSpecification;
  102548. public function __construct(
  102549. string $code,
  102550. VersionSpecificationInterface $versionSpecification,
  102551. ?array $configuration = null
  102552. ) {
  102553. $this->codeSample = new CodeSample($code, $configuration);
  102554. $this->versionSpecification = $versionSpecification;
  102555. }
  102556. public function getCode(): string
  102557. {
  102558. return $this->codeSample->getCode();
  102559. }
  102560. public function getConfiguration(): ?array
  102561. {
  102562. return $this->codeSample->getConfiguration();
  102563. }
  102564. public function isSuitableFor(int $version): bool
  102565. {
  102566. return $this->versionSpecification->isSatisfiedBy($version);
  102567. }
  102568. }
  102569. <?php
  102570. declare(strict_types=1);
  102571. namespace PhpCsFixer\FixerDefinition;
  102572. /**
  102573. @readonly
  102574. */
  102575. final class VersionSpecification implements VersionSpecificationInterface
  102576. {
  102577. private ?int $minimum;
  102578. private ?int $maximum;
  102579. public function __construct(?int $minimum = null, ?int $maximum = null)
  102580. {
  102581. if (null === $minimum && null === $maximum) {
  102582. throw new \InvalidArgumentException('Minimum or maximum need to be specified.');
  102583. }
  102584. if (null !== $minimum && 1 > $minimum) {
  102585. throw new \InvalidArgumentException('Minimum needs to be either null or an integer greater than 0.');
  102586. }
  102587. if (null !== $maximum) {
  102588. if (1 > $maximum) {
  102589. throw new \InvalidArgumentException('Maximum needs to be either null or an integer greater than 0.');
  102590. }
  102591. if (null !== $minimum && $maximum < $minimum) {
  102592. throw new \InvalidArgumentException('Maximum should not be lower than the minimum.');
  102593. }
  102594. }
  102595. $this->minimum = $minimum;
  102596. $this->maximum = $maximum;
  102597. }
  102598. public function isSatisfiedBy(int $version): bool
  102599. {
  102600. if (null !== $this->minimum && $version < $this->minimum) {
  102601. return false;
  102602. }
  102603. if (null !== $this->maximum && $version > $this->maximum) {
  102604. return false;
  102605. }
  102606. return true;
  102607. }
  102608. }
  102609. <?php
  102610. declare(strict_types=1);
  102611. namespace PhpCsFixer\FixerDefinition;
  102612. interface FileSpecificCodeSampleInterface extends CodeSampleInterface
  102613. {
  102614. public function getSplFileInfo(): \SplFileInfo;
  102615. }
  102616. <?php
  102617. declare(strict_types=1);
  102618. namespace PhpCsFixer;
  102619. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  102620. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  102621. use PhpCsFixer\Fixer\FixerInterface;
  102622. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  102623. use PhpCsFixer\RuleSet\RuleSetInterface;
  102624. use Symfony\Component\Finder\Finder as SymfonyFinder;
  102625. use Symfony\Component\Finder\SplFileInfo;
  102626. final class FixerFactory
  102627. {
  102628. private FixerNameValidator $nameValidator;
  102629. private array $fixers = [];
  102630. private array $fixersByName = [];
  102631. public function __construct()
  102632. {
  102633. $this->nameValidator = new FixerNameValidator();
  102634. }
  102635. public function setWhitespacesConfig(WhitespacesFixerConfig $config): self
  102636. {
  102637. foreach ($this->fixers as $fixer) {
  102638. if ($fixer instanceof WhitespacesAwareFixerInterface) {
  102639. $fixer->setWhitespacesConfig($config);
  102640. }
  102641. }
  102642. return $this;
  102643. }
  102644. public function getFixers(): array
  102645. {
  102646. $this->fixers = Utils::sortFixers($this->fixers);
  102647. return $this->fixers;
  102648. }
  102649. public function registerBuiltInFixers(): self
  102650. {
  102651. static $builtInFixers = null;
  102652. if (null === $builtInFixers) {
  102653. $builtInFixers = [];
  102654. $finder = SymfonyFinder::create()->files()
  102655. ->in(__DIR__.'/Fixer')
  102656. ->exclude(['Internal'])
  102657. ->name('*Fixer.php')
  102658. ->depth(1)
  102659. ;
  102660. foreach ($finder as $file) {
  102661. $relativeNamespace = $file->getRelativePath();
  102662. $fixerClass = 'PhpCsFixer\Fixer\\'.('' !== $relativeNamespace ? $relativeNamespace.'\\' : '').$file->getBasename('.php');
  102663. $builtInFixers[] = $fixerClass;
  102664. }
  102665. }
  102666. foreach ($builtInFixers as $class) {
  102667. $fixer = new $class();
  102668. $this->registerFixer($fixer, false);
  102669. }
  102670. return $this;
  102671. }
  102672. public function registerCustomFixers(iterable $fixers): self
  102673. {
  102674. foreach ($fixers as $fixer) {
  102675. $this->registerFixer($fixer, true);
  102676. }
  102677. return $this;
  102678. }
  102679. public function registerFixer(FixerInterface $fixer, bool $isCustom): self
  102680. {
  102681. $name = $fixer->getName();
  102682. if (isset($this->fixersByName[$name])) {
  102683. throw new \UnexpectedValueException(\sprintf('Fixer named "%s" is already registered.', $name));
  102684. }
  102685. if (!$this->nameValidator->isValid($name, $isCustom)) {
  102686. throw new \UnexpectedValueException(\sprintf('Fixer named "%s" has invalid name.', $name));
  102687. }
  102688. $this->fixers[] = $fixer;
  102689. $this->fixersByName[$name] = $fixer;
  102690. return $this;
  102691. }
  102692. public function useRuleSet(RuleSetInterface $ruleSet): self
  102693. {
  102694. $fixers = [];
  102695. $fixersByName = [];
  102696. $fixerConflicts = [];
  102697. $fixerNames = array_keys($ruleSet->getRules());
  102698. foreach ($fixerNames as $name) {
  102699. if (!\array_key_exists($name, $this->fixersByName)) {
  102700. throw new \UnexpectedValueException(\sprintf('Rule "%s" does not exist.', $name));
  102701. }
  102702. $fixer = $this->fixersByName[$name];
  102703. $config = $ruleSet->getRuleConfiguration($name);
  102704. if (null !== $config) {
  102705. if ($fixer instanceof ConfigurableFixerInterface) {
  102706. if (\count($config) < 1) {
  102707. throw new InvalidFixerConfigurationException($fixer->getName(), 'Configuration must be an array and may not be empty.');
  102708. }
  102709. $fixer->configure($config);
  102710. } else {
  102711. throw new InvalidFixerConfigurationException($fixer->getName(), 'Is not configurable.');
  102712. }
  102713. }
  102714. $fixers[] = $fixer;
  102715. $fixersByName[$name] = $fixer;
  102716. $conflicts = array_intersect($this->getFixersConflicts($fixer), $fixerNames);
  102717. if (\count($conflicts) > 0) {
  102718. $fixerConflicts[$name] = $conflicts;
  102719. }
  102720. }
  102721. if (\count($fixerConflicts) > 0) {
  102722. throw new \UnexpectedValueException($this->generateConflictMessage($fixerConflicts));
  102723. }
  102724. $this->fixers = $fixers;
  102725. $this->fixersByName = $fixersByName;
  102726. return $this;
  102727. }
  102728. public function hasRule(string $name): bool
  102729. {
  102730. return isset($this->fixersByName[$name]);
  102731. }
  102732. private function getFixersConflicts(FixerInterface $fixer): array
  102733. {
  102734. static $conflictMap = [
  102735. 'blank_lines_before_namespace' => [
  102736. 'no_blank_lines_before_namespace',
  102737. 'single_blank_line_before_namespace',
  102738. ],
  102739. 'no_blank_lines_before_namespace' => ['single_blank_line_before_namespace'],
  102740. 'single_import_per_statement' => ['group_import'],
  102741. ];
  102742. $fixerName = $fixer->getName();
  102743. return \array_key_exists($fixerName, $conflictMap) ? $conflictMap[$fixerName] : [];
  102744. }
  102745. private function generateConflictMessage(array $fixerConflicts): string
  102746. {
  102747. $message = 'Rule contains conflicting fixers:';
  102748. $report = [];
  102749. foreach ($fixerConflicts as $fixer => $fixers) {
  102750. $report[$fixer] = array_filter(
  102751. $fixers,
  102752. static fn (string $candidate): bool => !\array_key_exists($candidate, $report) || !\in_array($fixer, $report[$candidate], true)
  102753. );
  102754. if (\count($report[$fixer]) > 0) {
  102755. $message .= \sprintf("\n- \"%s\" with %s", $fixer, Utils::naturalLanguageJoin($report[$fixer]));
  102756. }
  102757. }
  102758. return $message;
  102759. }
  102760. }
  102761. <?php
  102762. declare(strict_types=1);
  102763. namespace PhpCsFixer;
  102764. use PhpCsFixer\Fixer\FixerInterface;
  102765. use PhpCsFixer\Tokenizer\Token;
  102766. final class Utils
  102767. {
  102768. private static array $deprecations = [];
  102769. private function __construct()
  102770. {
  102771. }
  102772. public static function camelCaseToUnderscore(string $string): string
  102773. {
  102774. return mb_strtolower(Preg::replace('/(?<!^)(?<!_)((?=[\p{Lu}][^\p{Lu}])|(?<![\p{Lu}])(?=[\p{Lu}]))/', '_', $string));
  102775. }
  102776. public static function calculateTrailingWhitespaceIndent(Token $token): string
  102777. {
  102778. if (!$token->isWhitespace()) {
  102779. throw new \InvalidArgumentException(\sprintf('The given token must be whitespace, got "%s".', $token->getName()));
  102780. }
  102781. $str = strrchr(
  102782. str_replace(["\r\n", "\r"], "\n", $token->getContent()),
  102783. "\n"
  102784. );
  102785. if (false === $str) {
  102786. return '';
  102787. }
  102788. return ltrim($str, "\n");
  102789. }
  102790. /**
  102791. @template
  102792. @template
  102793. */
  102794. public static function stableSort(array $elements, callable $getComparedValue, callable $compareValues): array
  102795. {
  102796. array_walk($elements, static function (&$element, int $index) use ($getComparedValue): void {
  102797. $element = [$element, $index, $getComparedValue($element)];
  102798. });
  102799. usort($elements, static function ($a, $b) use ($compareValues): int {
  102800. $comparison = $compareValues($a[2], $b[2]);
  102801. if (0 !== $comparison) {
  102802. return $comparison;
  102803. }
  102804. return $a[1] <=> $b[1];
  102805. });
  102806. return array_map(static fn (array $item) => $item[0], $elements);
  102807. }
  102808. public static function sortFixers(array $fixers): array
  102809. {
  102810. return self::stableSort(
  102811. $fixers,
  102812. static fn (FixerInterface $fixer): int => $fixer->getPriority(),
  102813. static fn (int $a, int $b): int => $b <=> $a
  102814. );
  102815. }
  102816. public static function naturalLanguageJoin(array $names, string $wrapper = '"'): string
  102817. {
  102818. if (0 === \count($names)) {
  102819. throw new \InvalidArgumentException('Array of names cannot be empty.');
  102820. }
  102821. if (\strlen($wrapper) > 1) {
  102822. throw new \InvalidArgumentException('Wrapper should be a single-char string or empty.');
  102823. }
  102824. $names = array_map(static fn (string $name): string => \sprintf('%2$s%1$s%2$s', $name, $wrapper), $names);
  102825. $last = array_pop($names);
  102826. if (\count($names) > 0) {
  102827. return implode(', ', $names).' and '.$last;
  102828. }
  102829. return $last;
  102830. }
  102831. public static function naturalLanguageJoinWithBackticks(array $names): string
  102832. {
  102833. return self::naturalLanguageJoin($names, '`');
  102834. }
  102835. public static function isFutureModeEnabled(): bool
  102836. {
  102837. return filter_var(
  102838. getenv('PHP_CS_FIXER_FUTURE_MODE'),
  102839. FILTER_VALIDATE_BOOL
  102840. );
  102841. }
  102842. public static function triggerDeprecation(\Exception $futureException): void
  102843. {
  102844. if (self::isFutureModeEnabled()) {
  102845. throw new \RuntimeException(
  102846. 'Your are using something deprecated, see previous exception. Aborting execution because `PHP_CS_FIXER_FUTURE_MODE` environment variable is set.',
  102847. 0,
  102848. $futureException
  102849. );
  102850. }
  102851. $message = $futureException->getMessage();
  102852. self::$deprecations[$message] = true;
  102853. @trigger_error($message, E_USER_DEPRECATED);
  102854. }
  102855. public static function getTriggeredDeprecations(): array
  102856. {
  102857. $triggeredDeprecations = array_keys(self::$deprecations);
  102858. sort($triggeredDeprecations);
  102859. return $triggeredDeprecations;
  102860. }
  102861. public static function convertArrayTypeToList(string $type): string
  102862. {
  102863. $parts = explode('[]', $type);
  102864. $count = \count($parts) - 1;
  102865. return str_repeat('list<', $count).$parts[0].str_repeat('>', $count);
  102866. }
  102867. public static function toString($value): string
  102868. {
  102869. return \is_array($value)
  102870. ? self::arrayToString($value)
  102871. : self::scalarToString($value);
  102872. }
  102873. private static function scalarToString($value): string
  102874. {
  102875. $str = var_export($value, true);
  102876. return Preg::replace('/\bNULL\b/', 'null', $str);
  102877. }
  102878. private static function arrayToString(array $value): string
  102879. {
  102880. if (0 === \count($value)) {
  102881. return '[]';
  102882. }
  102883. $isHash = !array_is_list($value);
  102884. $str = '[';
  102885. foreach ($value as $k => $v) {
  102886. if ($isHash) {
  102887. $str .= self::scalarToString($k).' => ';
  102888. }
  102889. $str .= \is_array($v)
  102890. ? self::arrayToString($v).', '
  102891. : self::scalarToString($v).', ';
  102892. }
  102893. return substr($str, 0, -2).']';
  102894. }
  102895. }
  102896. <?php
  102897. declare(strict_types=1);
  102898. namespace PhpCsFixer;
  102899. interface ToolInfoInterface
  102900. {
  102901. public function getComposerInstallationDetails(): array;
  102902. public function getComposerVersion(): string;
  102903. public function getVersion(): string;
  102904. public function isInstalledAsPhar(): bool;
  102905. public function isInstalledByComposer(): bool;
  102906. public function isRunInsideDocker(): bool;
  102907. public function getPharDownloadUri(string $version): string;
  102908. }
  102909. <?php
  102910. declare(strict_types=1);
  102911. namespace PhpCsFixer;
  102912. use PhpCsFixer\DocBlock\Annotation;
  102913. use PhpCsFixer\DocBlock\DocBlock;
  102914. use PhpCsFixer\DocBlock\TypeExpression;
  102915. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  102916. use PhpCsFixer\Fixer\ConfigurableFixerTrait;
  102917. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
  102918. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  102919. use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
  102920. use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
  102921. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  102922. use PhpCsFixer\Tokenizer\CT;
  102923. use PhpCsFixer\Tokenizer\Token;
  102924. use PhpCsFixer\Tokenizer\Tokens;
  102925. /**
  102926. @phpstan-type
  102927. @phpstan-type
  102928. @phpstan-type
  102929. @implements
  102930. */
  102931. abstract class AbstractPhpdocToTypeDeclarationFixer extends AbstractFixer implements ConfigurableFixerInterface
  102932. {
  102933. /**
  102934. @use */
  102935. use ConfigurableFixerTrait;
  102936. private const REGEX_CLASS = '(?:\\\?+'.TypeExpression::REGEX_IDENTIFIER
  102937. .'(\\\\'.TypeExpression::REGEX_IDENTIFIER.')*+)';
  102938. private array $versionSpecificTypes = [
  102939. 'void' => 7_01_00,
  102940. 'iterable' => 7_01_00,
  102941. 'object' => 7_02_00,
  102942. 'mixed' => 8_00_00,
  102943. 'never' => 8_01_00,
  102944. ];
  102945. private array $scalarTypes = [
  102946. 'bool' => true,
  102947. 'float' => true,
  102948. 'int' => true,
  102949. 'string' => true,
  102950. ];
  102951. private static array $syntaxValidationCache = [];
  102952. public function isRisky(): bool
  102953. {
  102954. return true;
  102955. }
  102956. abstract protected function isSkippedType(string $type): bool;
  102957. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  102958. {
  102959. return new FixerConfigurationResolver([
  102960. (new FixerOptionBuilder('scalar_types', 'Fix also scalar types; may have unexpected behaviour due to PHP bad type coercion system.'))
  102961. ->setAllowedTypes(['bool'])
  102962. ->setDefault(true)
  102963. ->getOption(),
  102964. (new FixerOptionBuilder('union_types', 'Fix also union types; turned on by default on PHP >= 8.0.0.'))
  102965. ->setAllowedTypes(['bool'])
  102966. ->setDefault(\PHP_VERSION_ID >= 8_00_00)
  102967. ->getOption(),
  102968. (new FixerOptionBuilder('types_map', 'Map of custom types, e.g. template types from PHPStan.'))
  102969. ->setAllowedTypes(['array<string, string>'])
  102970. ->setDefault([])
  102971. ->getOption(),
  102972. ]);
  102973. }
  102974. protected function findFunctionDocComment(Tokens $tokens, int $index): ?int
  102975. {
  102976. do {
  102977. $index = $tokens->getPrevNonWhitespace($index);
  102978. } while ($tokens[$index]->isGivenKind([
  102979. T_COMMENT,
  102980. T_ABSTRACT,
  102981. T_FINAL,
  102982. T_PRIVATE,
  102983. T_PROTECTED,
  102984. T_PUBLIC,
  102985. T_STATIC,
  102986. ]));
  102987. if ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
  102988. return $index;
  102989. }
  102990. return null;
  102991. }
  102992. protected function getAnnotationsFromDocComment(string $name, Tokens $tokens, int $docCommentIndex): array
  102993. {
  102994. $namespacesAnalyzer = new NamespacesAnalyzer();
  102995. $namespace = $namespacesAnalyzer->getNamespaceAt($tokens, $docCommentIndex);
  102996. $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
  102997. $namespaceUses = $namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace);
  102998. $doc = new DocBlock(
  102999. $tokens[$docCommentIndex]->getContent(),
  103000. $namespace,
  103001. $namespaceUses
  103002. );
  103003. return $doc->getAnnotationsOfType($name);
  103004. }
  103005. protected function createTypeDeclarationTokens(string $type, bool $isNullable): array
  103006. {
  103007. $newTokens = [];
  103008. if (true === $isNullable && 'mixed' !== $type) {
  103009. $newTokens[] = new Token([CT::T_NULLABLE_TYPE, '?']);
  103010. }
  103011. $newTokens = array_merge(
  103012. $newTokens,
  103013. $this->createTokensFromRawType($type)->toArray()
  103014. );
  103015. foreach ($newTokens as $i => $token) {
  103016. if ($token->isGivenKind(T_STRING)) {
  103017. $typeUnqualified = $token->getContent();
  103018. if (
  103019. (isset($this->scalarTypes[$typeUnqualified]) || isset($this->versionSpecificTypes[$typeUnqualified]))
  103020. && isset($newTokens[$i - 1])
  103021. && '\\' === $newTokens[$i - 1]->getContent()
  103022. ) {
  103023. unset($newTokens[$i - 1]);
  103024. }
  103025. }
  103026. }
  103027. return array_values($newTokens);
  103028. }
  103029. abstract protected function createTokensFromRawType(string $type): Tokens;
  103030. protected function getCommonTypeInfo(TypeExpression $typesExpression, bool $isReturnType): ?array
  103031. {
  103032. $commonType = $typesExpression->getCommonType();
  103033. $isNullable = $typesExpression->allowsNull();
  103034. if (null === $commonType) {
  103035. return null;
  103036. }
  103037. if ($isNullable && 'void' === $commonType) {
  103038. return null;
  103039. }
  103040. if ('static' === $commonType && (!$isReturnType || \PHP_VERSION_ID < 8_00_00)) {
  103041. $commonType = 'self';
  103042. }
  103043. if ($this->isSkippedType($commonType)) {
  103044. return null;
  103045. }
  103046. if (isset($this->versionSpecificTypes[$commonType]) && \PHP_VERSION_ID < $this->versionSpecificTypes[$commonType]) {
  103047. return null;
  103048. }
  103049. if (\array_key_exists($commonType, $this->configuration['types_map'])) {
  103050. $commonType = $this->configuration['types_map'][$commonType];
  103051. }
  103052. if (isset($this->scalarTypes[$commonType])) {
  103053. if (false === $this->configuration['scalar_types']) {
  103054. return null;
  103055. }
  103056. } elseif (!Preg::match('/^'.self::REGEX_CLASS.'$/', $commonType)) {
  103057. return null;
  103058. }
  103059. return ['commonType' => $commonType, 'isNullable' => $isNullable];
  103060. }
  103061. protected function getUnionTypes(TypeExpression $typesExpression, bool $isReturnType): ?string
  103062. {
  103063. if (\PHP_VERSION_ID < 8_00_00) {
  103064. return null;
  103065. }
  103066. if (!$typesExpression->isUnionType()) {
  103067. return null;
  103068. }
  103069. if (false === $this->configuration['union_types']) {
  103070. return null;
  103071. }
  103072. $types = $typesExpression->getTypes();
  103073. $isNullable = $typesExpression->allowsNull();
  103074. $unionTypes = [];
  103075. $containsOtherThanIterableType = false;
  103076. $containsOtherThanEmptyType = false;
  103077. foreach ($types as $type) {
  103078. if ('null' === $type) {
  103079. continue;
  103080. }
  103081. if ($this->isSkippedType($type)) {
  103082. return null;
  103083. }
  103084. if (isset($this->versionSpecificTypes[$type]) && \PHP_VERSION_ID < $this->versionSpecificTypes[$type]) {
  103085. return null;
  103086. }
  103087. $typeExpression = new TypeExpression($type, null, []);
  103088. $commonType = $typeExpression->getCommonType();
  103089. if (!$containsOtherThanIterableType && !\in_array($commonType, ['array', \Traversable::class, 'iterable'], true)) {
  103090. $containsOtherThanIterableType = true;
  103091. }
  103092. if ($isReturnType && !$containsOtherThanEmptyType && !\in_array($commonType, ['null', 'void', 'never'], true)) {
  103093. $containsOtherThanEmptyType = true;
  103094. }
  103095. if (!$isNullable && $typesExpression->allowsNull()) {
  103096. $isNullable = true;
  103097. }
  103098. $unionTypes[] = $commonType;
  103099. }
  103100. if (!$containsOtherThanIterableType) {
  103101. return null;
  103102. }
  103103. if ($isReturnType && !$containsOtherThanEmptyType) {
  103104. return null;
  103105. }
  103106. if ($isNullable) {
  103107. $unionTypes[] = 'null';
  103108. }
  103109. return implode($typesExpression->getTypesGlue(), array_unique($unionTypes));
  103110. }
  103111. final protected function isValidSyntax(string $code): bool
  103112. {
  103113. if (!isset(self::$syntaxValidationCache[$code])) {
  103114. try {
  103115. Tokens::fromCode($code);
  103116. self::$syntaxValidationCache[$code] = true;
  103117. } catch (\ParseError $e) {
  103118. self::$syntaxValidationCache[$code] = false;
  103119. }
  103120. }
  103121. return self::$syntaxValidationCache[$code];
  103122. }
  103123. }
  103124. <?php
  103125. declare(strict_types=1);
  103126. namespace PhpCsFixer;
  103127. /**
  103128. @readonly
  103129. */
  103130. final class WhitespacesFixerConfig
  103131. {
  103132. private string $indent;
  103133. private string $lineEnding;
  103134. public function __construct(string $indent = ' ', string $lineEnding = "\n")
  103135. {
  103136. if (!\in_array($indent, [' ', ' ', "\t"], true)) {
  103137. throw new \InvalidArgumentException('Invalid "indent" param, expected tab or two or four spaces.');
  103138. }
  103139. if (!\in_array($lineEnding, ["\n", "\r\n"], true)) {
  103140. throw new \InvalidArgumentException('Invalid "lineEnding" param, expected "\n" or "\r\n".');
  103141. }
  103142. $this->indent = $indent;
  103143. $this->lineEnding = $lineEnding;
  103144. }
  103145. public function getIndent(): string
  103146. {
  103147. return $this->indent;
  103148. }
  103149. public function getLineEnding(): string
  103150. {
  103151. return $this->lineEnding;
  103152. }
  103153. }
  103154. <?php
  103155. declare(strict_types=1);
  103156. namespace PhpCsFixer;
  103157. use PhpCsFixer\ConfigurationException\RequiredFixerConfigurationException;
  103158. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  103159. use PhpCsFixer\Fixer\FixerInterface;
  103160. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  103161. use PhpCsFixer\Tokenizer\Tokens;
  103162. abstract class AbstractFixer implements FixerInterface
  103163. {
  103164. protected WhitespacesFixerConfig $whitespacesConfig;
  103165. public function __construct()
  103166. {
  103167. if ($this instanceof ConfigurableFixerInterface) {
  103168. try {
  103169. $this->configure([]);
  103170. } catch (RequiredFixerConfigurationException $e) {
  103171. }
  103172. }
  103173. if ($this instanceof WhitespacesAwareFixerInterface) {
  103174. $this->whitespacesConfig = $this->getDefaultWhitespacesFixerConfig();
  103175. }
  103176. }
  103177. final public function fix(\SplFileInfo $file, Tokens $tokens): void
  103178. {
  103179. if ($this instanceof ConfigurableFixerInterface && property_exists($this, 'configuration') && null === $this->configuration) {
  103180. throw new RequiredFixerConfigurationException($this->getName(), 'Configuration is required.');
  103181. }
  103182. if (0 < $tokens->count() && $this->isCandidate($tokens) && $this->supports($file)) {
  103183. $this->applyFix($file, $tokens);
  103184. }
  103185. }
  103186. public function isRisky(): bool
  103187. {
  103188. return false;
  103189. }
  103190. public function getName(): string
  103191. {
  103192. $nameParts = explode('\\', static::class);
  103193. $name = substr(end($nameParts), 0, -\strlen('Fixer'));
  103194. return Utils::camelCaseToUnderscore($name);
  103195. }
  103196. public function getPriority(): int
  103197. {
  103198. return 0;
  103199. }
  103200. public function supports(\SplFileInfo $file): bool
  103201. {
  103202. return true;
  103203. }
  103204. public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
  103205. {
  103206. if (!$this instanceof WhitespacesAwareFixerInterface) {
  103207. throw new \LogicException('Cannot run method for class not implementing "PhpCsFixer\Fixer\WhitespacesAwareFixerInterface".');
  103208. }
  103209. $this->whitespacesConfig = $config;
  103210. }
  103211. abstract protected function applyFix(\SplFileInfo $file, Tokens $tokens): void;
  103212. private function getDefaultWhitespacesFixerConfig(): WhitespacesFixerConfig
  103213. {
  103214. static $defaultWhitespacesFixerConfig = null;
  103215. if (null === $defaultWhitespacesFixerConfig) {
  103216. $defaultWhitespacesFixerConfig = new WhitespacesFixerConfig(' ', "\n");
  103217. }
  103218. return $defaultWhitespacesFixerConfig;
  103219. }
  103220. }
  103221. <?php
  103222. declare(strict_types=1);
  103223. namespace PhpCsFixer;
  103224. final class Preg
  103225. {
  103226. /**
  103227. @param-out($flags is PREG_OFFSET_CAPTURE? array<array-key, array{string, 0|positive-int}|array{'', -1}>: ($flags is PREG_UNMATCHED_AS_NULL? array<array-key, string|null>: ($flags is int-mask<PREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL>&768? array<array-key, array{string, 0|positive-int}|array{null, -1}>: array<array-key, string>))) $matches
  103228. */
  103229. public static function match(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): bool
  103230. {
  103231. $result = @preg_match(self::addUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  103232. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103233. return 1 === $result;
  103234. }
  103235. $result = @preg_match(self::removeUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  103236. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103237. return 1 === $result;
  103238. }
  103239. throw self::newPregException(preg_last_error(), preg_last_error_msg(), __METHOD__, $pattern);
  103240. }
  103241. /**
  103242. @param-out($flags is PREG_PATTERN_ORDER? array<list<string>>: ($flags is PREG_SET_ORDER? list<array<string>>: ($flags is int-mask<PREG_PATTERN_ORDER, PREG_OFFSET_CAPTURE>&(256|257)? array<list<array{string, int}>>: ($flags is int-mask<PREG_SET_ORDER, PREG_OFFSET_CAPTURE>&258? list<array<array{string, int}>>: ($flags is int-mask<PREG_PATTERN_ORDER, PREG_UNMATCHED_AS_NULL>&(512|513)? array<list<?string>>: ($flags is int-mask<PREG_SET_ORDER, PREG_UNMATCHED_AS_NULL>&514? list<array<?string>>: ($flags is int-mask<PREG_SET_ORDER, PREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL>&770? list<array<array{?string, int}>>: ($flags is 0 ? array<list<string>> : array<mixed>)))))))) $matches
  103243. */
  103244. public static function matchAll(string $pattern, string $subject, ?array &$matches = null, int $flags = PREG_PATTERN_ORDER, int $offset = 0): int
  103245. {
  103246. $result = @preg_match_all(self::addUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  103247. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103248. return $result;
  103249. }
  103250. $result = @preg_match_all(self::removeUtf8Modifier($pattern), $subject, $matches, $flags, $offset);
  103251. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103252. return $result;
  103253. }
  103254. throw self::newPregException(preg_last_error(), preg_last_error_msg(), __METHOD__, $pattern);
  103255. }
  103256. /**
  103257. @param-out
  103258. */
  103259. public static function replace(string $pattern, string $replacement, string $subject, int $limit = -1, ?int &$count = null): string
  103260. {
  103261. $result = @preg_replace(self::addUtf8Modifier($pattern), $replacement, $subject, $limit, $count);
  103262. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  103263. return $result;
  103264. }
  103265. $result = @preg_replace(self::removeUtf8Modifier($pattern), $replacement, $subject, $limit, $count);
  103266. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  103267. return $result;
  103268. }
  103269. throw self::newPregException(preg_last_error(), preg_last_error_msg(), __METHOD__, $pattern);
  103270. }
  103271. /**
  103272. @param-out
  103273. */
  103274. public static function replaceCallback(string $pattern, callable $callback, string $subject, int $limit = -1, ?int &$count = null): string
  103275. {
  103276. $result = @preg_replace_callback(self::addUtf8Modifier($pattern), $callback, $subject, $limit, $count);
  103277. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  103278. return $result;
  103279. }
  103280. $result = @preg_replace_callback(self::removeUtf8Modifier($pattern), $callback, $subject, $limit, $count);
  103281. if (null !== $result && PREG_NO_ERROR === preg_last_error()) {
  103282. return $result;
  103283. }
  103284. throw self::newPregException(preg_last_error(), preg_last_error_msg(), __METHOD__, $pattern);
  103285. }
  103286. public static function split(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
  103287. {
  103288. $result = @preg_split(self::addUtf8Modifier($pattern), $subject, $limit, $flags);
  103289. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103290. return $result;
  103291. }
  103292. $result = @preg_split(self::removeUtf8Modifier($pattern), $subject, $limit, $flags);
  103293. if (false !== $result && PREG_NO_ERROR === preg_last_error()) {
  103294. return $result;
  103295. }
  103296. throw self::newPregException(preg_last_error(), preg_last_error_msg(), __METHOD__, $pattern);
  103297. }
  103298. private static function addUtf8Modifier(string $pattern): string
  103299. {
  103300. return $pattern.'u';
  103301. }
  103302. private static function removeUtf8Modifier(string $pattern): string
  103303. {
  103304. if ('' === $pattern) {
  103305. return '';
  103306. }
  103307. $delimiter = $pattern[0];
  103308. $endDelimiterPosition = strrpos($pattern, $delimiter);
  103309. \assert(\is_int($endDelimiterPosition));
  103310. return substr($pattern, 0, $endDelimiterPosition).str_replace('u', '', substr($pattern, $endDelimiterPosition));
  103311. }
  103312. private static function newPregException(int $error, string $errorMsg, string $method, string $pattern): PregException
  103313. {
  103314. $result = null;
  103315. $errorMessage = null;
  103316. try {
  103317. $result = ExecutorWithoutErrorHandler::execute(static fn () => preg_match($pattern, ''));
  103318. } catch (ExecutorWithoutErrorHandlerException $e) {
  103319. $result = false;
  103320. $errorMessage = $e->getMessage();
  103321. }
  103322. if (false !== $result) {
  103323. return new PregException(\sprintf('Unknown error occurred when calling %s: %s.', $method, $errorMsg), $error);
  103324. }
  103325. $code = preg_last_error();
  103326. $message = \sprintf(
  103327. '(code: %d) %s',
  103328. $code,
  103329. preg_replace('~preg_[a-z_]+[()]{2}: ~', '', $errorMessage)
  103330. );
  103331. return new PregException(
  103332. \sprintf('%s(): Invalid PCRE pattern "%s": %s (version: %s)', $method, $pattern, $message, PCRE_VERSION),
  103333. $code
  103334. );
  103335. }
  103336. }
  103337. <?php
  103338. declare(strict_types=1);
  103339. namespace PhpCsFixer\Error;
  103340. /**
  103341. @readonly
  103342. */
  103343. final class Error implements \JsonSerializable
  103344. {
  103345. public const TYPE_INVALID = 1;
  103346. public const TYPE_EXCEPTION = 2;
  103347. public const TYPE_LINT = 3;
  103348. private int $type;
  103349. private string $filePath;
  103350. private ?\Throwable $source;
  103351. private array $appliedFixers;
  103352. private ?string $diff;
  103353. public function __construct(int $type, string $filePath, ?\Throwable $source = null, array $appliedFixers = [], ?string $diff = null)
  103354. {
  103355. $this->type = $type;
  103356. $this->filePath = $filePath;
  103357. $this->source = $source;
  103358. $this->appliedFixers = $appliedFixers;
  103359. $this->diff = $diff;
  103360. }
  103361. public function getFilePath(): string
  103362. {
  103363. return $this->filePath;
  103364. }
  103365. public function getSource(): ?\Throwable
  103366. {
  103367. return $this->source;
  103368. }
  103369. public function getType(): int
  103370. {
  103371. return $this->type;
  103372. }
  103373. public function getAppliedFixers(): array
  103374. {
  103375. return $this->appliedFixers;
  103376. }
  103377. public function getDiff(): ?string
  103378. {
  103379. return $this->diff;
  103380. }
  103381. public function jsonSerialize(): array
  103382. {
  103383. return [
  103384. 'type' => $this->type,
  103385. 'filePath' => $this->filePath,
  103386. 'source' => null !== $this->source
  103387. ? [
  103388. 'class' => \get_class($this->source),
  103389. 'message' => $this->source->getMessage(),
  103390. 'code' => $this->source->getCode(),
  103391. 'file' => $this->source->getFile(),
  103392. 'line' => $this->source->getLine(),
  103393. ]
  103394. : null,
  103395. 'appliedFixers' => $this->appliedFixers,
  103396. 'diff' => $this->diff,
  103397. ];
  103398. }
  103399. }
  103400. <?php
  103401. declare(strict_types=1);
  103402. namespace PhpCsFixer\Error;
  103403. /**
  103404. @readonly
  103405. */
  103406. final class SourceExceptionFactory
  103407. {
  103408. public static function fromArray(array $error): \Throwable
  103409. {
  103410. $exceptionClass = $error['class'];
  103411. try {
  103412. $exception = new $exceptionClass($error['message'], $error['code']);
  103413. if (
  103414. $exception->getMessage() !== $error['message']
  103415. || $exception->getCode() !== $error['code']
  103416. ) {
  103417. throw new \RuntimeException('Failed to create exception from array. Message and code are not the same.');
  103418. }
  103419. } catch (\Throwable $e) {
  103420. $exception = new \RuntimeException(
  103421. \sprintf('[%s] %s', $exceptionClass, $error['message']),
  103422. $error['code']
  103423. );
  103424. }
  103425. try {
  103426. $exceptionReflection = new \ReflectionClass($exception);
  103427. foreach (['file', 'line'] as $property) {
  103428. $propertyReflection = $exceptionReflection->getProperty($property);
  103429. $propertyReflection->setAccessible(true);
  103430. $propertyReflection->setValue($exception, $error[$property]);
  103431. $propertyReflection->setAccessible(false);
  103432. }
  103433. } catch (\Throwable $reflectionException) {
  103434. }
  103435. return $exception;
  103436. }
  103437. }
  103438. <?php
  103439. declare(strict_types=1);
  103440. namespace PhpCsFixer\Error;
  103441. final class ErrorsManager
  103442. {
  103443. private array $errors = [];
  103444. public function getInvalidErrors(): array
  103445. {
  103446. return array_filter($this->errors, static fn (Error $error): bool => Error::TYPE_INVALID === $error->getType());
  103447. }
  103448. public function getExceptionErrors(): array
  103449. {
  103450. return array_filter($this->errors, static fn (Error $error): bool => Error::TYPE_EXCEPTION === $error->getType());
  103451. }
  103452. public function getLintErrors(): array
  103453. {
  103454. return array_filter($this->errors, static fn (Error $error): bool => Error::TYPE_LINT === $error->getType());
  103455. }
  103456. public function forPath(string $path): array
  103457. {
  103458. return array_values(array_filter($this->errors, static fn (Error $error): bool => $path === $error->getFilePath()));
  103459. }
  103460. public function isEmpty(): bool
  103461. {
  103462. return [] === $this->errors;
  103463. }
  103464. public function report(Error $error): void
  103465. {
  103466. $this->errors[] = $error;
  103467. }
  103468. }
  103469. <?php
  103470. declare(strict_types=1);
  103471. namespace PhpCsFixer;
  103472. use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
  103473. use PhpCsFixer\Tokenizer\Tokens;
  103474. abstract class AbstractFunctionReferenceFixer extends AbstractFixer
  103475. {
  103476. private ?FunctionsAnalyzer $functionsAnalyzer = null;
  103477. public function isCandidate(Tokens $tokens): bool
  103478. {
  103479. return $tokens->isTokenKindFound(T_STRING);
  103480. }
  103481. public function isRisky(): bool
  103482. {
  103483. return true;
  103484. }
  103485. protected function find(string $functionNameToSearch, Tokens $tokens, int $start = 0, ?int $end = null): ?array
  103486. {
  103487. if (null === $this->functionsAnalyzer) {
  103488. $this->functionsAnalyzer = new FunctionsAnalyzer();
  103489. }
  103490. $end ??= $tokens->count();
  103491. $candidateSequence = [[T_STRING, $functionNameToSearch], '('];
  103492. $matches = $tokens->findSequence($candidateSequence, $start, $end, false);
  103493. if (null === $matches) {
  103494. return null;
  103495. }
  103496. [$functionName, $openParenthesis] = array_keys($matches);
  103497. if (!$this->functionsAnalyzer->isGlobalFunctionCall($tokens, $functionName)) {
  103498. return $this->find($functionNameToSearch, $tokens, $openParenthesis, $end);
  103499. }
  103500. return [$functionName, $openParenthesis, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis)];
  103501. }
  103502. }
  103503. <?php
  103504. declare(strict_types=1);
  103505. namespace PhpCsFixer;
  103506. final class Hasher
  103507. {
  103508. private function __construct()
  103509. {
  103510. }
  103511. public static function calculate(string $code): string
  103512. {
  103513. return \PHP_VERSION_ID >= 8_01_00
  103514. ? hash('xxh128', $code)
  103515. : md5($code);
  103516. }
  103517. }
  103518. <?php
  103519. declare(strict_types=1);
  103520. namespace PhpCsFixer;
  103521. use PhpCsFixer\Console\Application;
  103522. final class ToolInfo implements ToolInfoInterface
  103523. {
  103524. public const COMPOSER_PACKAGE_NAME = 'friendsofphp/php-cs-fixer';
  103525. public const COMPOSER_LEGACY_PACKAGE_NAME = 'fabpot/php-cs-fixer';
  103526. private ?array $composerInstallationDetails = null;
  103527. private ?bool $isInstalledByComposer = null;
  103528. public function getComposerInstallationDetails(): array
  103529. {
  103530. if (!$this->isInstalledByComposer()) {
  103531. throw new \LogicException('Cannot get composer version for tool not installed by composer.');
  103532. }
  103533. if (null === $this->composerInstallationDetails) {
  103534. $composerInstalled = json_decode(file_get_contents($this->getComposerInstalledFile()), true, 512, JSON_THROW_ON_ERROR);
  103535. $packages = $composerInstalled['packages'] ?? $composerInstalled;
  103536. foreach ($packages as $package) {
  103537. if (\in_array($package['name'], [self::COMPOSER_PACKAGE_NAME, self::COMPOSER_LEGACY_PACKAGE_NAME], true)) {
  103538. $this->composerInstallationDetails = $package;
  103539. break;
  103540. }
  103541. }
  103542. }
  103543. return $this->composerInstallationDetails;
  103544. }
  103545. public function getComposerVersion(): string
  103546. {
  103547. $package = $this->getComposerInstallationDetails();
  103548. $versionSuffix = '';
  103549. if (isset($package['dist']['reference'])) {
  103550. $versionSuffix = '#'.$package['dist']['reference'];
  103551. }
  103552. return $package['version'].$versionSuffix;
  103553. }
  103554. public function getVersion(): string
  103555. {
  103556. if ($this->isInstalledByComposer()) {
  103557. return Application::VERSION.':'.$this->getComposerVersion();
  103558. }
  103559. return Application::VERSION;
  103560. }
  103561. public function isInstalledAsPhar(): bool
  103562. {
  103563. return str_starts_with(__DIR__, 'phar://');
  103564. }
  103565. public function isInstalledByComposer(): bool
  103566. {
  103567. if (null === $this->isInstalledByComposer) {
  103568. $this->isInstalledByComposer = !$this->isInstalledAsPhar() && file_exists($this->getComposerInstalledFile());
  103569. }
  103570. return $this->isInstalledByComposer;
  103571. }
  103572. public function isRunInsideDocker(): bool
  103573. {
  103574. return str_starts_with(__FILE__, '/fixer/') && is_file('/.dockerenv');
  103575. }
  103576. public function getPharDownloadUri(string $version): string
  103577. {
  103578. return \sprintf(
  103579. 'https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases/download/%s/php-cs-fixer.phar',
  103580. $version
  103581. );
  103582. }
  103583. private function getComposerInstalledFile(): string
  103584. {
  103585. return __DIR__.'/../../../composer/installed.json';
  103586. }
  103587. }
  103588. <?php
  103589. declare(strict_types=1);
  103590. namespace PhpCsFixer\Console;
  103591. use PhpCsFixer\Console\Command\CheckCommand;
  103592. use PhpCsFixer\Console\Command\DescribeCommand;
  103593. use PhpCsFixer\Console\Command\FixCommand;
  103594. use PhpCsFixer\Console\Command\HelpCommand;
  103595. use PhpCsFixer\Console\Command\ListFilesCommand;
  103596. use PhpCsFixer\Console\Command\ListSetsCommand;
  103597. use PhpCsFixer\Console\Command\SelfUpdateCommand;
  103598. use PhpCsFixer\Console\Command\WorkerCommand;
  103599. use PhpCsFixer\Console\SelfUpdate\GithubClient;
  103600. use PhpCsFixer\Console\SelfUpdate\NewVersionChecker;
  103601. use PhpCsFixer\PharChecker;
  103602. use PhpCsFixer\Runner\Parallel\WorkerException;
  103603. use PhpCsFixer\ToolInfo;
  103604. use PhpCsFixer\Utils;
  103605. use Symfony\Component\Console\Application as BaseApplication;
  103606. use Symfony\Component\Console\Command\Command;
  103607. use Symfony\Component\Console\Command\ListCommand;
  103608. use Symfony\Component\Console\Input\InputInterface;
  103609. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  103610. use Symfony\Component\Console\Output\OutputInterface;
  103611. final class Application extends BaseApplication
  103612. {
  103613. public const NAME = 'PHP CS Fixer';
  103614. public const VERSION = '3.82.2';
  103615. public const VERSION_CODENAME = 'Alexander';
  103616. /**
  103617. @readonly
  103618. */
  103619. private ToolInfo $toolInfo;
  103620. private ?Command $executedCommand = null;
  103621. public function __construct()
  103622. {
  103623. parent::__construct(self::NAME, self::VERSION);
  103624. $this->toolInfo = new ToolInfo();
  103625. $this->add(new DescribeCommand());
  103626. $this->add(new CheckCommand($this->toolInfo));
  103627. $this->add(new FixCommand($this->toolInfo));
  103628. $this->add(new ListFilesCommand($this->toolInfo));
  103629. $this->add(new ListSetsCommand());
  103630. $this->add(new SelfUpdateCommand(
  103631. new NewVersionChecker(new GithubClient()),
  103632. $this->toolInfo,
  103633. new PharChecker()
  103634. ));
  103635. $this->add(new WorkerCommand($this->toolInfo));
  103636. }
  103637. public static function getMajorVersion(): int
  103638. {
  103639. return (int) explode('.', self::VERSION)[0];
  103640. }
  103641. public function doRun(InputInterface $input, OutputInterface $output): int
  103642. {
  103643. $stdErr = $output instanceof ConsoleOutputInterface
  103644. ? $output->getErrorOutput()
  103645. : ($input->hasParameterOption('--format', true) && 'txt' !== $input->getParameterOption('--format', null, true) ? null : $output);
  103646. if (null !== $stdErr) {
  103647. $warningsDetector = new WarningsDetector($this->toolInfo);
  103648. $warningsDetector->detectOldVendor();
  103649. $warningsDetector->detectOldMajor();
  103650. $warnings = $warningsDetector->getWarnings();
  103651. if (\count($warnings) > 0) {
  103652. foreach ($warnings as $warning) {
  103653. $stdErr->writeln(\sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', $warning));
  103654. }
  103655. $stdErr->writeln('');
  103656. }
  103657. }
  103658. $result = parent::doRun($input, $output);
  103659. if (
  103660. null !== $stdErr
  103661. && $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE
  103662. ) {
  103663. $triggeredDeprecations = Utils::getTriggeredDeprecations();
  103664. if (\count($triggeredDeprecations) > 0) {
  103665. $stdErr->writeln('');
  103666. $stdErr->writeln($stdErr->isDecorated() ? '<bg=yellow;fg=black;>Detected deprecations in use:</>' : 'Detected deprecations in use:');
  103667. foreach ($triggeredDeprecations as $deprecation) {
  103668. $stdErr->writeln(\sprintf('- %s', $deprecation));
  103669. }
  103670. }
  103671. }
  103672. return $result;
  103673. }
  103674. public static function getAbout(bool $decorated = false): string
  103675. {
  103676. $longVersion = \sprintf('%s <info>%s</info>', self::NAME, self::VERSION);
  103677. $commit = '97de337e3f3d7524f2f398d31ef9fab643d04692';
  103678. $versionCommit = '';
  103679. if ('@'.'git-commit@' !== $commit) { /**
  103680. @phpstan-ignore-line */
  103681. $versionCommit = substr($commit, 0, 7);
  103682. }
  103683. $about = implode('', [
  103684. $longVersion,
  103685. $versionCommit ? \sprintf(' <info>(%s)</info>', $versionCommit) : '',
  103686. self::VERSION_CODENAME ? \sprintf(' <info>%s</info>', self::VERSION_CODENAME) : '',
  103687. ' by <comment>Fabien Potencier</comment>, <comment>Dariusz Ruminski</comment> and <comment>contributors</comment>.',
  103688. ]);
  103689. if (false === $decorated) {
  103690. return strip_tags($about);
  103691. }
  103692. return $about;
  103693. }
  103694. public static function getAboutWithRuntime(bool $decorated = false): string
  103695. {
  103696. $about = self::getAbout(true)."\nPHP runtime: <info>".PHP_VERSION.'</info>';
  103697. if (false === $decorated) {
  103698. return strip_tags($about);
  103699. }
  103700. return $about;
  103701. }
  103702. public function getLongVersion(): string
  103703. {
  103704. return self::getAboutWithRuntime(true);
  103705. }
  103706. protected function getDefaultCommands(): array
  103707. {
  103708. return [new HelpCommand(), new ListCommand()];
  103709. }
  103710. protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
  103711. {
  103712. $this->executedCommand = $command;
  103713. return parent::doRunCommand($command, $input, $output);
  103714. }
  103715. protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void
  103716. {
  103717. if ($this->executedCommand instanceof WorkerCommand) {
  103718. $output->writeln(WorkerCommand::ERROR_PREFIX.json_encode(
  103719. [
  103720. 'class' => \get_class($e),
  103721. 'message' => $e->getMessage(),
  103722. 'file' => $e->getFile(),
  103723. 'line' => $e->getLine(),
  103724. 'code' => $e->getCode(),
  103725. 'trace' => $e->getTraceAsString(),
  103726. ]
  103727. ));
  103728. return;
  103729. }
  103730. parent::doRenderThrowable($e, $output);
  103731. if ($output->isVeryVerbose() && $e instanceof WorkerException) {
  103732. $output->writeln('<comment>Original trace from worker:</comment>');
  103733. $output->writeln('');
  103734. $output->writeln($e->getOriginalTraceAsString());
  103735. $output->writeln('');
  103736. }
  103737. }
  103738. }
  103739. <?php
  103740. declare(strict_types=1);
  103741. namespace PhpCsFixer\Console\SelfUpdate;
  103742. interface NewVersionCheckerInterface
  103743. {
  103744. public function getLatestVersion(): string;
  103745. public function getLatestVersionOfMajor(int $majorVersion): ?string;
  103746. public function compareVersions(string $versionA, string $versionB): int;
  103747. }
  103748. <?php
  103749. declare(strict_types=1);
  103750. namespace PhpCsFixer\Console\SelfUpdate;
  103751. interface GithubClientInterface
  103752. {
  103753. public function getTags(): array;
  103754. }
  103755. <?php
  103756. declare(strict_types=1);
  103757. namespace PhpCsFixer\Console\SelfUpdate;
  103758. /**
  103759. @readonly
  103760. */
  103761. final class GithubClient implements GithubClientInterface
  103762. {
  103763. private string $url;
  103764. public function __construct(string $url = 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tags')
  103765. {
  103766. $this->url = $url;
  103767. }
  103768. public function getTags(): array
  103769. {
  103770. $result = @file_get_contents(
  103771. $this->url,
  103772. false,
  103773. stream_context_create([
  103774. 'http' => [
  103775. 'header' => 'User-Agent: PHP-CS-Fixer/PHP-CS-Fixer',
  103776. ],
  103777. ])
  103778. );
  103779. if (false === $result) {
  103780. throw new \RuntimeException(\sprintf('Failed to load tags at "%s".', $this->url));
  103781. }
  103782. $result = json_decode($result, true);
  103783. if (JSON_ERROR_NONE !== json_last_error()) {
  103784. throw new \RuntimeException(\sprintf(
  103785. 'Failed to read response from "%s" as JSON: %s.',
  103786. $this->url,
  103787. json_last_error_msg()
  103788. ));
  103789. }
  103790. return array_map(
  103791. static fn (array $tagData): string => $tagData['name'],
  103792. $result
  103793. );
  103794. }
  103795. }
  103796. <?php
  103797. declare(strict_types=1);
  103798. namespace PhpCsFixer\Console\SelfUpdate;
  103799. use Composer\Semver\Comparator;
  103800. use Composer\Semver\Semver;
  103801. use Composer\Semver\VersionParser;
  103802. final class NewVersionChecker implements NewVersionCheckerInterface
  103803. {
  103804. private GithubClientInterface $githubClient;
  103805. private VersionParser $versionParser;
  103806. private ?array $availableVersions = null;
  103807. public function __construct(GithubClientInterface $githubClient)
  103808. {
  103809. $this->githubClient = $githubClient;
  103810. $this->versionParser = new VersionParser();
  103811. }
  103812. public function getLatestVersion(): string
  103813. {
  103814. $this->retrieveAvailableVersions();
  103815. return $this->availableVersions[0];
  103816. }
  103817. public function getLatestVersionOfMajor(int $majorVersion): ?string
  103818. {
  103819. $this->retrieveAvailableVersions();
  103820. $semverConstraint = '^'.$majorVersion;
  103821. foreach ($this->availableVersions as $availableVersion) {
  103822. if (Semver::satisfies($availableVersion, $semverConstraint)) {
  103823. return $availableVersion;
  103824. }
  103825. }
  103826. return null;
  103827. }
  103828. public function compareVersions(string $versionA, string $versionB): int
  103829. {
  103830. $versionA = $this->versionParser->normalize($versionA);
  103831. $versionB = $this->versionParser->normalize($versionB);
  103832. if (Comparator::lessThan($versionA, $versionB)) {
  103833. return -1;
  103834. }
  103835. if (Comparator::greaterThan($versionA, $versionB)) {
  103836. return 1;
  103837. }
  103838. return 0;
  103839. }
  103840. private function retrieveAvailableVersions(): void
  103841. {
  103842. if (null !== $this->availableVersions) {
  103843. return;
  103844. }
  103845. foreach ($this->githubClient->getTags() as $version) {
  103846. try {
  103847. $this->versionParser->normalize($version);
  103848. if ('stable' === VersionParser::parseStability($version)) {
  103849. $this->availableVersions[] = $version;
  103850. }
  103851. } catch (\UnexpectedValueException $exception) {
  103852. }
  103853. }
  103854. $versions = Semver::rsort($this->availableVersions);
  103855. \assert(array_is_list($versions));
  103856. $this->availableVersions = $versions;
  103857. }
  103858. }
  103859. <?php
  103860. declare(strict_types=1);
  103861. namespace PhpCsFixer\Console;
  103862. use PhpCsFixer\ToolInfo;
  103863. use PhpCsFixer\ToolInfoInterface;
  103864. final class WarningsDetector
  103865. {
  103866. private ToolInfoInterface $toolInfo;
  103867. private array $warnings = [];
  103868. public function __construct(ToolInfoInterface $toolInfo)
  103869. {
  103870. $this->toolInfo = $toolInfo;
  103871. }
  103872. public function detectOldMajor(): void
  103873. {
  103874. }
  103875. public function detectOldVendor(): void
  103876. {
  103877. if ($this->toolInfo->isInstalledByComposer()) {
  103878. $details = $this->toolInfo->getComposerInstallationDetails();
  103879. if (ToolInfo::COMPOSER_LEGACY_PACKAGE_NAME === $details['name']) {
  103880. $this->warnings[] = \sprintf(
  103881. 'You are running PHP CS Fixer installed with old vendor `%s`. Please update to `%s`.',
  103882. ToolInfo::COMPOSER_LEGACY_PACKAGE_NAME,
  103883. ToolInfo::COMPOSER_PACKAGE_NAME
  103884. );
  103885. }
  103886. }
  103887. }
  103888. public function getWarnings(): array
  103889. {
  103890. if (0 === \count($this->warnings)) {
  103891. return [];
  103892. }
  103893. return array_values(array_unique(array_merge(
  103894. $this->warnings,
  103895. ['If you need help while solving warnings, ask at https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/discussions/, we will help you!']
  103896. )));
  103897. }
  103898. }
  103899. <?php
  103900. declare(strict_types=1);
  103901. namespace PhpCsFixer\Console\Output\Progress;
  103902. use PhpCsFixer\Console\Output\OutputContext;
  103903. use PhpCsFixer\Runner\Event\FileProcessed;
  103904. use Symfony\Component\Console\Output\OutputInterface;
  103905. final class DotsOutput implements ProgressOutputInterface
  103906. {
  103907. private const EVENT_STATUS_MAP = [
  103908. FileProcessed::STATUS_NO_CHANGES => ['symbol' => '.', 'format' => '%s', 'description' => 'no changes'],
  103909. FileProcessed::STATUS_FIXED => ['symbol' => 'F', 'format' => '<fg=green>%s</fg=green>', 'description' => 'fixed'],
  103910. FileProcessed::STATUS_SKIPPED => ['symbol' => 'S', 'format' => '<fg=cyan>%s</fg=cyan>', 'description' => 'skipped (cached or empty file)'],
  103911. FileProcessed::STATUS_INVALID => ['symbol' => 'I', 'format' => '<bg=red>%s</bg=red>', 'description' => 'invalid file syntax (file ignored)'],
  103912. FileProcessed::STATUS_EXCEPTION => ['symbol' => 'E', 'format' => '<bg=red>%s</bg=red>', 'description' => 'error'],
  103913. FileProcessed::STATUS_LINT => ['symbol' => 'E', 'format' => '<bg=red>%s</bg=red>', 'description' => 'error'],
  103914. ];
  103915. /**
  103916. @readonly */
  103917. private OutputContext $context;
  103918. private int $processedFiles = 0;
  103919. private int $symbolsPerLine;
  103920. public function __construct(OutputContext $context)
  103921. {
  103922. $this->context = $context;
  103923. $this->symbolsPerLine = max(1, $context->getTerminalWidth() - \strlen((string) $context->getFilesCount()) * 2 - 11);
  103924. }
  103925. public function __sleep(): array
  103926. {
  103927. throw new \BadMethodCallException('Cannot serialize '.self::class);
  103928. }
  103929. public function __wakeup(): void
  103930. {
  103931. throw new \BadMethodCallException('Cannot unserialize '.self::class);
  103932. }
  103933. public function onFixerFileProcessed(FileProcessed $event): void
  103934. {
  103935. $status = self::EVENT_STATUS_MAP[$event->getStatus()];
  103936. $this->getOutput()->write($this->getOutput()->isDecorated() ? \sprintf($status['format'], $status['symbol']) : $status['symbol']);
  103937. ++$this->processedFiles;
  103938. $symbolsOnCurrentLine = $this->processedFiles % $this->symbolsPerLine;
  103939. $isLast = $this->processedFiles === $this->context->getFilesCount();
  103940. if (0 === $symbolsOnCurrentLine || $isLast) {
  103941. $this->getOutput()->write(\sprintf(
  103942. '%s %'.\strlen((string) $this->context->getFilesCount()).'d / %d (%3d%%)',
  103943. $isLast && 0 !== $symbolsOnCurrentLine ? str_repeat(' ', $this->symbolsPerLine - $symbolsOnCurrentLine) : '',
  103944. $this->processedFiles,
  103945. $this->context->getFilesCount(),
  103946. round($this->processedFiles / $this->context->getFilesCount() * 100)
  103947. ));
  103948. if (!$isLast) {
  103949. $this->getOutput()->writeln('');
  103950. }
  103951. }
  103952. }
  103953. public function printLegend(): void
  103954. {
  103955. $symbols = [];
  103956. foreach (self::EVENT_STATUS_MAP as $status) {
  103957. $symbol = $status['symbol'];
  103958. if (isset($symbols[$symbol])) {
  103959. continue;
  103960. }
  103961. $symbols[$symbol] = \sprintf('%s-%s', $this->getOutput()->isDecorated() ? \sprintf($status['format'], $symbol) : $symbol, $status['description']);
  103962. }
  103963. $this->getOutput()->write(\sprintf("\nLegend: %s\n", implode(', ', $symbols)));
  103964. }
  103965. private function getOutput(): OutputInterface
  103966. {
  103967. return $this->context->getOutput();
  103968. }
  103969. }
  103970. <?php
  103971. declare(strict_types=1);
  103972. namespace PhpCsFixer\Console\Output\Progress;
  103973. use PhpCsFixer\Runner\Event\FileProcessed;
  103974. interface ProgressOutputInterface
  103975. {
  103976. public function printLegend(): void;
  103977. public function onFixerFileProcessed(FileProcessed $event): void;
  103978. }
  103979. <?php
  103980. declare(strict_types=1);
  103981. namespace PhpCsFixer\Console\Output\Progress;
  103982. final class ProgressOutputType
  103983. {
  103984. public const NONE = 'none';
  103985. public const DOTS = 'dots';
  103986. public const BAR = 'bar';
  103987. public static function all(): array
  103988. {
  103989. return [
  103990. self::BAR,
  103991. self::DOTS,
  103992. self::NONE,
  103993. ];
  103994. }
  103995. }
  103996. <?php
  103997. declare(strict_types=1);
  103998. namespace PhpCsFixer\Console\Output\Progress;
  103999. use PhpCsFixer\Console\Output\OutputContext;
  104000. use PhpCsFixer\Runner\Event\FileProcessed;
  104001. use Symfony\Component\Console\Helper\ProgressBar;
  104002. /**
  104003. @readonly
  104004. */
  104005. final class PercentageBarOutput implements ProgressOutputInterface
  104006. {
  104007. /**
  104008. @readonly */
  104009. private OutputContext $context;
  104010. private ProgressBar $progressBar;
  104011. public function __construct(OutputContext $context)
  104012. {
  104013. $this->context = $context;
  104014. $this->progressBar = new ProgressBar($context->getOutput(), $this->context->getFilesCount());
  104015. $this->progressBar->setBarCharacter('â–“');
  104016. $this->progressBar->setEmptyBarCharacter('â–‘');
  104017. $this->progressBar->setProgressCharacter('');
  104018. $this->progressBar->setFormat('normal');
  104019. $this->progressBar->start();
  104020. }
  104021. public function __sleep(): array
  104022. {
  104023. throw new \BadMethodCallException('Cannot serialize '.self::class);
  104024. }
  104025. public function __wakeup(): void
  104026. {
  104027. throw new \BadMethodCallException('Cannot unserialize '.self::class);
  104028. }
  104029. public function onFixerFileProcessed(FileProcessed $event): void
  104030. {
  104031. $this->progressBar->advance(1);
  104032. if ($this->progressBar->getProgress() === $this->progressBar->getMaxSteps()) {
  104033. $this->context->getOutput()->write("\n\n");
  104034. }
  104035. }
  104036. public function printLegend(): void {}
  104037. }
  104038. <?php
  104039. declare(strict_types=1);
  104040. namespace PhpCsFixer\Console\Output\Progress;
  104041. use PhpCsFixer\Console\Output\OutputContext;
  104042. /**
  104043. @readonly
  104044. */
  104045. final class ProgressOutputFactory
  104046. {
  104047. private const OUTPUT_TYPE_MAP = [
  104048. ProgressOutputType::NONE => NullOutput::class,
  104049. ProgressOutputType::DOTS => DotsOutput::class,
  104050. ProgressOutputType::BAR => PercentageBarOutput::class,
  104051. ];
  104052. public function create(string $outputType, OutputContext $context): ProgressOutputInterface
  104053. {
  104054. if (null === $context->getOutput()) {
  104055. $outputType = ProgressOutputType::NONE;
  104056. }
  104057. if (!$this->isBuiltInType($outputType)) {
  104058. throw new \InvalidArgumentException(
  104059. \sprintf(
  104060. 'Something went wrong, "%s" output type is not supported',
  104061. $outputType
  104062. )
  104063. );
  104064. }
  104065. $outputClass = self::OUTPUT_TYPE_MAP[$outputType];
  104066. return new $outputClass($context);
  104067. }
  104068. private function isBuiltInType(string $outputType): bool
  104069. {
  104070. return \in_array($outputType, ProgressOutputType::all(), true);
  104071. }
  104072. }
  104073. <?php
  104074. declare(strict_types=1);
  104075. namespace PhpCsFixer\Console\Output\Progress;
  104076. use PhpCsFixer\Runner\Event\FileProcessed;
  104077. /**
  104078. @readonly
  104079. */
  104080. final class NullOutput implements ProgressOutputInterface
  104081. {
  104082. public function printLegend(): void {}
  104083. public function onFixerFileProcessed(FileProcessed $event): void {}
  104084. }
  104085. <?php
  104086. declare(strict_types=1);
  104087. namespace PhpCsFixer\Console\Output;
  104088. use PhpCsFixer\Differ\DiffConsoleFormatter;
  104089. use PhpCsFixer\Error\Error;
  104090. use PhpCsFixer\Linter\LintingException;
  104091. use Symfony\Component\Console\Command\Command;
  104092. use Symfony\Component\Console\Formatter\OutputFormatter;
  104093. use Symfony\Component\Console\Output\OutputInterface;
  104094. /**
  104095. @readonly
  104096. */
  104097. final class ErrorOutput
  104098. {
  104099. private OutputInterface $output;
  104100. private bool $isDecorated;
  104101. public function __construct(OutputInterface $output)
  104102. {
  104103. $this->output = $output;
  104104. $this->isDecorated = $output->isDecorated();
  104105. }
  104106. public function listErrors(string $process, array $errors): void
  104107. {
  104108. $this->output->writeln(['', \sprintf(
  104109. 'Files that were not fixed due to errors reported during %s:',
  104110. $process
  104111. )]);
  104112. $showDetails = $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
  104113. $showTrace = $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
  104114. foreach ($errors as $i => $error) {
  104115. $this->output->writeln(\sprintf('%4d) %s', $i + 1, $error->getFilePath()));
  104116. $e = $error->getSource();
  104117. if (!$showDetails || null === $e) {
  104118. continue;
  104119. }
  104120. $class = \sprintf('[%s]', \get_class($e));
  104121. $message = $e->getMessage();
  104122. $code = $e->getCode();
  104123. if (0 !== $code) {
  104124. $message .= " ({$code})";
  104125. }
  104126. $length = max(\strlen($class), \strlen($message));
  104127. $lines = [
  104128. '',
  104129. $class,
  104130. $message,
  104131. '',
  104132. ];
  104133. $this->output->writeln('');
  104134. foreach ($lines as $line) {
  104135. if (\strlen($line) < $length) {
  104136. $line .= str_repeat(' ', $length - \strlen($line));
  104137. }
  104138. $this->output->writeln(\sprintf(' <error> %s </error>', $this->prepareOutput($line)));
  104139. }
  104140. if ($showTrace && !$e instanceof LintingException) {
  104141. $this->output->writeln('');
  104142. $stackTrace = $e->getTrace();
  104143. foreach ($stackTrace as $trace) {
  104144. if (isset($trace['class']) && Command::class === $trace['class'] && 'run' === $trace['function']) {
  104145. $this->output->writeln(' [ ... ]');
  104146. break;
  104147. }
  104148. $this->outputTrace($trace);
  104149. }
  104150. }
  104151. if (Error::TYPE_LINT === $error->getType() && 0 < \count($error->getAppliedFixers())) {
  104152. $this->output->writeln('');
  104153. $this->output->writeln(\sprintf(' Applied fixers: <comment>%s</comment>', implode(', ', $error->getAppliedFixers())));
  104154. $diff = $error->getDiff();
  104155. if (null !== $diff) {
  104156. $diffFormatter = new DiffConsoleFormatter(
  104157. $this->isDecorated,
  104158. \sprintf(
  104159. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  104160. PHP_EOL,
  104161. PHP_EOL
  104162. )
  104163. );
  104164. $this->output->writeln($diffFormatter->format($diff));
  104165. }
  104166. }
  104167. }
  104168. }
  104169. private function outputTrace(array $trace): void
  104170. {
  104171. if (isset($trace['class'], $trace['type'], $trace['function'])) {
  104172. $this->output->writeln(\sprintf(
  104173. ' <comment>%s</comment>%s<comment>%s()</comment>',
  104174. $this->prepareOutput($trace['class']),
  104175. $this->prepareOutput($trace['type']),
  104176. $this->prepareOutput($trace['function'])
  104177. ));
  104178. } elseif (isset($trace['function'])) {
  104179. $this->output->writeln(\sprintf(' <comment>%s()</comment>', $this->prepareOutput($trace['function'])));
  104180. }
  104181. if (isset($trace['file'])) {
  104182. $this->output->writeln(\sprintf(' in <info>%s</info> at line <info>%d</info>', $this->prepareOutput($trace['file']), $trace['line']));
  104183. }
  104184. }
  104185. private function prepareOutput(string $string): string
  104186. {
  104187. return $this->isDecorated
  104188. ? OutputFormatter::escape($string)
  104189. : $string;
  104190. }
  104191. }
  104192. <?php
  104193. declare(strict_types=1);
  104194. namespace PhpCsFixer\Console\Output;
  104195. use Symfony\Component\Console\Output\OutputInterface;
  104196. /**
  104197. @readonly
  104198. */
  104199. final class OutputContext
  104200. {
  104201. private ?OutputInterface $output;
  104202. private int $terminalWidth;
  104203. private int $filesCount;
  104204. public function __construct(
  104205. ?OutputInterface $output,
  104206. int $terminalWidth,
  104207. int $filesCount
  104208. ) {
  104209. $this->output = $output;
  104210. $this->terminalWidth = $terminalWidth;
  104211. $this->filesCount = $filesCount;
  104212. }
  104213. public function getOutput(): ?OutputInterface
  104214. {
  104215. return $this->output;
  104216. }
  104217. public function getTerminalWidth(): int
  104218. {
  104219. return $this->terminalWidth;
  104220. }
  104221. public function getFilesCount(): int
  104222. {
  104223. return $this->filesCount;
  104224. }
  104225. }
  104226. <?php
  104227. declare(strict_types=1);
  104228. namespace PhpCsFixer\Console;
  104229. use PhpCsFixer\Cache\CacheManagerInterface;
  104230. use PhpCsFixer\Cache\Directory;
  104231. use PhpCsFixer\Cache\DirectoryInterface;
  104232. use PhpCsFixer\Cache\FileCacheManager;
  104233. use PhpCsFixer\Cache\FileHandler;
  104234. use PhpCsFixer\Cache\NullCacheManager;
  104235. use PhpCsFixer\Cache\Signature;
  104236. use PhpCsFixer\ConfigInterface;
  104237. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  104238. use PhpCsFixer\Console\Output\Progress\ProgressOutputType;
  104239. use PhpCsFixer\Console\Report\FixReport\ReporterFactory;
  104240. use PhpCsFixer\Console\Report\FixReport\ReporterInterface;
  104241. use PhpCsFixer\Differ\DifferInterface;
  104242. use PhpCsFixer\Differ\NullDiffer;
  104243. use PhpCsFixer\Differ\UnifiedDiffer;
  104244. use PhpCsFixer\Finder;
  104245. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  104246. use PhpCsFixer\Fixer\FixerInterface;
  104247. use PhpCsFixer\FixerFactory;
  104248. use PhpCsFixer\Linter\Linter;
  104249. use PhpCsFixer\Linter\LinterInterface;
  104250. use PhpCsFixer\ParallelAwareConfigInterface;
  104251. use PhpCsFixer\RuleSet\RuleSet;
  104252. use PhpCsFixer\RuleSet\RuleSetInterface;
  104253. use PhpCsFixer\Runner\Parallel\ParallelConfig;
  104254. use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
  104255. use PhpCsFixer\StdinFileInfo;
  104256. use PhpCsFixer\ToolInfoInterface;
  104257. use PhpCsFixer\UnsupportedPhpVersionAllowedConfigInterface;
  104258. use PhpCsFixer\Utils;
  104259. use PhpCsFixer\WhitespacesFixerConfig;
  104260. use PhpCsFixer\WordMatcher;
  104261. use Symfony\Component\Filesystem\Filesystem;
  104262. use Symfony\Component\Finder\Finder as SymfonyFinder;
  104263. /**
  104264. @phpstan-type
  104265. */
  104266. final class ConfigurationResolver
  104267. {
  104268. public const PATH_MODE_OVERRIDE = 'override';
  104269. public const PATH_MODE_INTERSECTION = 'intersection';
  104270. private ?bool $allowRisky = null;
  104271. private ?ConfigInterface $config = null;
  104272. private ?string $configFile = null;
  104273. private string $cwd;
  104274. private ConfigInterface $defaultConfig;
  104275. private ?ReporterInterface $reporter = null;
  104276. private ?bool $isStdIn = null;
  104277. private ?bool $isDryRun = null;
  104278. private ?array $fixers = null;
  104279. private ?bool $configFinderIsOverridden = null;
  104280. private ToolInfoInterface $toolInfo;
  104281. private array $options = [
  104282. 'allow-risky' => null,
  104283. 'cache-file' => null,
  104284. 'config' => null,
  104285. 'diff' => null,
  104286. 'dry-run' => null,
  104287. 'format' => null,
  104288. 'path' => [],
  104289. 'path-mode' => self::PATH_MODE_OVERRIDE,
  104290. 'rules' => null,
  104291. 'sequential' => null,
  104292. 'show-progress' => null,
  104293. 'stop-on-violation' => null,
  104294. 'using-cache' => null,
  104295. 'allow-unsupported-php-version' => null,
  104296. 'verbosity' => null,
  104297. ];
  104298. private ?string $cacheFile = null;
  104299. private ?CacheManagerInterface $cacheManager = null;
  104300. private ?DifferInterface $differ = null;
  104301. private ?Directory $directory = null;
  104302. private ?iterable $finder = null;
  104303. private ?string $format = null;
  104304. private ?Linter $linter = null;
  104305. private ?array $path = null;
  104306. private $progress;
  104307. private ?RuleSet $ruleSet = null;
  104308. private ?bool $usingCache = null;
  104309. private ?bool $isUnsupportedPhpVersionAllowed = null;
  104310. private ?FixerFactory $fixerFactory = null;
  104311. public function __construct(
  104312. ConfigInterface $config,
  104313. array $options,
  104314. string $cwd,
  104315. ToolInfoInterface $toolInfo
  104316. ) {
  104317. $this->defaultConfig = $config;
  104318. $this->cwd = $cwd;
  104319. $this->toolInfo = $toolInfo;
  104320. foreach ($options as $name => $value) {
  104321. $this->setOption($name, $value);
  104322. }
  104323. }
  104324. public function getCacheFile(): ?string
  104325. {
  104326. if (!$this->getUsingCache()) {
  104327. return null;
  104328. }
  104329. if (null === $this->cacheFile) {
  104330. if (null === $this->options['cache-file']) {
  104331. $this->cacheFile = $this->getConfig()->getCacheFile();
  104332. } else {
  104333. $this->cacheFile = $this->options['cache-file'];
  104334. }
  104335. }
  104336. return $this->cacheFile;
  104337. }
  104338. public function getCacheManager(): CacheManagerInterface
  104339. {
  104340. if (null === $this->cacheManager) {
  104341. $cacheFile = $this->getCacheFile();
  104342. if (null === $cacheFile) {
  104343. $this->cacheManager = new NullCacheManager();
  104344. } else {
  104345. $this->cacheManager = new FileCacheManager(
  104346. new FileHandler($cacheFile),
  104347. new Signature(
  104348. PHP_VERSION,
  104349. $this->toolInfo->getVersion(),
  104350. $this->getConfig()->getIndent(),
  104351. $this->getConfig()->getLineEnding(),
  104352. $this->getRules()
  104353. ),
  104354. $this->isDryRun(),
  104355. $this->getDirectory()
  104356. );
  104357. }
  104358. }
  104359. return $this->cacheManager;
  104360. }
  104361. public function getConfig(): ConfigInterface
  104362. {
  104363. if (null === $this->config) {
  104364. foreach ($this->computeConfigFiles() as $configFile) {
  104365. if (!file_exists($configFile)) {
  104366. continue;
  104367. }
  104368. $configFileBasename = basename($configFile);
  104369. $deprecatedConfigs = [
  104370. '.php_cs' => '.php-cs-fixer.php',
  104371. '.php_cs.dist' => '.php-cs-fixer.dist.php',
  104372. ];
  104373. if (isset($deprecatedConfigs[$configFileBasename])) {
  104374. throw new InvalidConfigurationException("Configuration file `{$configFileBasename}` is outdated, rename to `{$deprecatedConfigs[$configFileBasename]}`.");
  104375. }
  104376. $this->config = self::separatedContextLessInclude($configFile);
  104377. $this->configFile = $configFile;
  104378. break;
  104379. }
  104380. if (null === $this->config) {
  104381. $this->config = $this->defaultConfig;
  104382. }
  104383. }
  104384. return $this->config;
  104385. }
  104386. public function getParallelConfig(): ParallelConfig
  104387. {
  104388. $config = $this->getConfig();
  104389. return true !== $this->options['sequential'] && $config instanceof ParallelAwareConfigInterface
  104390. ? $config->getParallelConfig()
  104391. : ParallelConfigFactory::sequential();
  104392. }
  104393. public function getConfigFile(): ?string
  104394. {
  104395. if (null === $this->configFile) {
  104396. $this->getConfig();
  104397. }
  104398. return $this->configFile;
  104399. }
  104400. public function getDiffer(): DifferInterface
  104401. {
  104402. if (null === $this->differ) {
  104403. $this->differ = (true === $this->options['diff']) ? new UnifiedDiffer() : new NullDiffer();
  104404. }
  104405. return $this->differ;
  104406. }
  104407. public function getDirectory(): DirectoryInterface
  104408. {
  104409. if (null === $this->directory) {
  104410. $path = $this->getCacheFile();
  104411. if (null === $path) {
  104412. $absolutePath = $this->cwd;
  104413. } else {
  104414. $filesystem = new Filesystem();
  104415. $absolutePath = $filesystem->isAbsolutePath($path)
  104416. ? $path
  104417. : $this->cwd.\DIRECTORY_SEPARATOR.$path;
  104418. $absolutePath = \dirname($absolutePath);
  104419. }
  104420. $this->directory = new Directory($absolutePath);
  104421. }
  104422. return $this->directory;
  104423. }
  104424. public function getFixers(): array
  104425. {
  104426. if (null === $this->fixers) {
  104427. $this->fixers = $this->createFixerFactory()
  104428. ->useRuleSet($this->getRuleSet())
  104429. ->setWhitespacesConfig(new WhitespacesFixerConfig($this->config->getIndent(), $this->config->getLineEnding()))
  104430. ->getFixers()
  104431. ;
  104432. if (false === $this->getRiskyAllowed()) {
  104433. $riskyFixers = array_map(
  104434. static fn (FixerInterface $fixer): string => $fixer->getName(),
  104435. array_filter(
  104436. $this->fixers,
  104437. static fn (FixerInterface $fixer): bool => $fixer->isRisky()
  104438. )
  104439. );
  104440. if (\count($riskyFixers) > 0) {
  104441. throw new InvalidConfigurationException(\sprintf('The rules contain risky fixers (%s), but they are not allowed to run. Perhaps you forget to use --allow-risky=yes option?', Utils::naturalLanguageJoin($riskyFixers)));
  104442. }
  104443. }
  104444. }
  104445. return $this->fixers;
  104446. }
  104447. public function getLinter(): LinterInterface
  104448. {
  104449. if (null === $this->linter) {
  104450. $this->linter = new Linter();
  104451. }
  104452. return $this->linter;
  104453. }
  104454. public function getPath(): array
  104455. {
  104456. if (null === $this->path) {
  104457. $filesystem = new Filesystem();
  104458. $cwd = $this->cwd;
  104459. if (1 === \count($this->options['path']) && '-' === $this->options['path'][0]) {
  104460. $this->path = $this->options['path'];
  104461. } else {
  104462. $this->path = array_map(
  104463. static function (string $rawPath) use ($cwd, $filesystem): string {
  104464. $path = trim($rawPath);
  104465. if ('' === $path) {
  104466. throw new InvalidConfigurationException("Invalid path: \"{$rawPath}\".");
  104467. }
  104468. $absolutePath = $filesystem->isAbsolutePath($path)
  104469. ? $path
  104470. : $cwd.\DIRECTORY_SEPARATOR.$path;
  104471. if (!file_exists($absolutePath)) {
  104472. throw new InvalidConfigurationException(\sprintf(
  104473. 'The path "%s" is not readable.',
  104474. $path
  104475. ));
  104476. }
  104477. return $absolutePath;
  104478. },
  104479. $this->options['path']
  104480. );
  104481. }
  104482. }
  104483. return $this->path;
  104484. }
  104485. public function getProgressType(): string
  104486. {
  104487. if (null === $this->progress) {
  104488. if ('txt' === $this->resolveFormat()) {
  104489. $progressType = $this->options['show-progress'];
  104490. if (null === $progressType) {
  104491. $progressType = $this->getConfig()->getHideProgress()
  104492. ? ProgressOutputType::NONE
  104493. : ProgressOutputType::BAR;
  104494. } elseif (!\in_array($progressType, ProgressOutputType::all(), true)) {
  104495. throw new InvalidConfigurationException(\sprintf(
  104496. 'The progress type "%s" is not defined, supported are %s.',
  104497. $progressType,
  104498. Utils::naturalLanguageJoin(ProgressOutputType::all())
  104499. ));
  104500. }
  104501. $this->progress = $progressType;
  104502. } else {
  104503. $this->progress = ProgressOutputType::NONE;
  104504. }
  104505. }
  104506. return $this->progress;
  104507. }
  104508. public function getReporter(): ReporterInterface
  104509. {
  104510. if (null === $this->reporter) {
  104511. $reporterFactory = new ReporterFactory();
  104512. $reporterFactory->registerBuiltInReporters();
  104513. $format = $this->resolveFormat();
  104514. try {
  104515. $this->reporter = $reporterFactory->getReporter($format);
  104516. } catch (\UnexpectedValueException $e) {
  104517. $formats = $reporterFactory->getFormats();
  104518. sort($formats);
  104519. throw new InvalidConfigurationException(\sprintf('The format "%s" is not defined, supported are %s.', $format, Utils::naturalLanguageJoin($formats)));
  104520. }
  104521. }
  104522. return $this->reporter;
  104523. }
  104524. public function getRiskyAllowed(): bool
  104525. {
  104526. if (null === $this->allowRisky) {
  104527. if (null === $this->options['allow-risky']) {
  104528. $this->allowRisky = $this->getConfig()->getRiskyAllowed();
  104529. } else {
  104530. $this->allowRisky = $this->resolveOptionBooleanValue('allow-risky');
  104531. }
  104532. }
  104533. return $this->allowRisky;
  104534. }
  104535. public function getRules(): array
  104536. {
  104537. return $this->getRuleSet()->getRules();
  104538. }
  104539. public function getUsingCache(): bool
  104540. {
  104541. if (null === $this->usingCache) {
  104542. if (null === $this->options['using-cache']) {
  104543. $this->usingCache = $this->getConfig()->getUsingCache();
  104544. } else {
  104545. $this->usingCache = $this->resolveOptionBooleanValue('using-cache');
  104546. }
  104547. }
  104548. $this->usingCache = $this->usingCache && $this->isCachingAllowedForRuntime();
  104549. return $this->usingCache;
  104550. }
  104551. public function getUnsupportedPhpVersionAllowed(): bool
  104552. {
  104553. if (null === $this->isUnsupportedPhpVersionAllowed) {
  104554. if (null === $this->options['allow-unsupported-php-version']) {
  104555. $config = $this->getConfig();
  104556. $this->isUnsupportedPhpVersionAllowed = $config instanceof UnsupportedPhpVersionAllowedConfigInterface
  104557. ? $config->getUnsupportedPhpVersionAllowed()
  104558. : false;
  104559. } else {
  104560. $this->isUnsupportedPhpVersionAllowed = $this->resolveOptionBooleanValue('allow-unsupported-php-version');
  104561. }
  104562. }
  104563. return $this->isUnsupportedPhpVersionAllowed;
  104564. }
  104565. public function getFinder(): iterable
  104566. {
  104567. if (null === $this->finder) {
  104568. $this->finder = $this->resolveFinder();
  104569. }
  104570. return $this->finder;
  104571. }
  104572. public function isDryRun(): bool
  104573. {
  104574. if (null === $this->isDryRun) {
  104575. if ($this->isStdIn()) {
  104576. $this->isDryRun = true;
  104577. } else {
  104578. $this->isDryRun = $this->options['dry-run'];
  104579. }
  104580. }
  104581. return $this->isDryRun;
  104582. }
  104583. public function shouldStopOnViolation(): bool
  104584. {
  104585. return $this->options['stop-on-violation'];
  104586. }
  104587. public function configFinderIsOverridden(): bool
  104588. {
  104589. if (null === $this->configFinderIsOverridden) {
  104590. $this->resolveFinder();
  104591. }
  104592. return $this->configFinderIsOverridden;
  104593. }
  104594. private function computeConfigFiles(): array
  104595. {
  104596. $configFile = $this->options['config'];
  104597. if (null !== $configFile) {
  104598. if (false === file_exists($configFile) || false === is_readable($configFile)) {
  104599. throw new InvalidConfigurationException(\sprintf('Cannot read config file "%s".', $configFile));
  104600. }
  104601. return [$configFile];
  104602. }
  104603. $path = $this->getPath();
  104604. if ($this->isStdIn() || 0 === \count($path)) {
  104605. $configDir = $this->cwd;
  104606. } elseif (1 < \count($path)) {
  104607. throw new InvalidConfigurationException('For multiple paths config parameter is required.');
  104608. } elseif (!is_file($path[0])) {
  104609. $configDir = $path[0];
  104610. } else {
  104611. $dirName = pathinfo($path[0], PATHINFO_DIRNAME);
  104612. $configDir = is_dir($dirName) ? $dirName : $path[0];
  104613. }
  104614. $candidates = [
  104615. $configDir.\DIRECTORY_SEPARATOR.'.php-cs-fixer.php',
  104616. $configDir.\DIRECTORY_SEPARATOR.'.php-cs-fixer.dist.php',
  104617. $configDir.\DIRECTORY_SEPARATOR.'.php_cs',
  104618. $configDir.\DIRECTORY_SEPARATOR.'.php_cs.dist',
  104619. ];
  104620. if ($configDir !== $this->cwd) {
  104621. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php-cs-fixer.php';
  104622. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php-cs-fixer.dist.php';
  104623. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php_cs';
  104624. $candidates[] = $this->cwd.\DIRECTORY_SEPARATOR.'.php_cs.dist';
  104625. }
  104626. return $candidates;
  104627. }
  104628. private function createFixerFactory(): FixerFactory
  104629. {
  104630. if (null === $this->fixerFactory) {
  104631. $fixerFactory = new FixerFactory();
  104632. $fixerFactory->registerBuiltInFixers();
  104633. $fixerFactory->registerCustomFixers($this->getConfig()->getCustomFixers());
  104634. $this->fixerFactory = $fixerFactory;
  104635. }
  104636. return $this->fixerFactory;
  104637. }
  104638. private function resolveFormat(): string
  104639. {
  104640. if (null === $this->format) {
  104641. $formatCandidate = $this->options['format'] ?? $this->getConfig()->getFormat();
  104642. $parts = explode(',', $formatCandidate);
  104643. if (\count($parts) > 2) {
  104644. throw new InvalidConfigurationException(\sprintf('The format "%s" is invalid.', $formatCandidate));
  104645. }
  104646. $this->format = $parts[0];
  104647. if ('@auto' === $this->format) {
  104648. $this->format = $parts[1] ?? 'txt';
  104649. if (filter_var(getenv('GITLAB_CI'), FILTER_VALIDATE_BOOL)) {
  104650. $this->format = 'gitlab';
  104651. }
  104652. }
  104653. }
  104654. return $this->format;
  104655. }
  104656. private function getRuleSet(): RuleSetInterface
  104657. {
  104658. if (null === $this->ruleSet) {
  104659. $rules = $this->parseRules();
  104660. $this->validateRules($rules);
  104661. $this->ruleSet = new RuleSet($rules);
  104662. }
  104663. return $this->ruleSet;
  104664. }
  104665. private function isStdIn(): bool
  104666. {
  104667. if (null === $this->isStdIn) {
  104668. $this->isStdIn = 1 === \count($this->options['path']) && '-' === $this->options['path'][0];
  104669. }
  104670. return $this->isStdIn;
  104671. }
  104672. /**
  104673. @template
  104674. */
  104675. private function iterableToTraversable(iterable $iterable): \Traversable
  104676. {
  104677. return \is_array($iterable) ? new \ArrayIterator($iterable) : $iterable;
  104678. }
  104679. private function parseRules(): array
  104680. {
  104681. if (null === $this->options['rules']) {
  104682. return $this->getConfig()->getRules();
  104683. }
  104684. $rules = trim($this->options['rules']);
  104685. if ('' === $rules) {
  104686. throw new InvalidConfigurationException('Empty rules value is not allowed.');
  104687. }
  104688. if (str_starts_with($rules, '{')) {
  104689. $rules = json_decode($rules, true);
  104690. if (JSON_ERROR_NONE !== json_last_error()) {
  104691. throw new InvalidConfigurationException(\sprintf('Invalid JSON rules input: "%s".', json_last_error_msg()));
  104692. }
  104693. return $rules;
  104694. }
  104695. $rules = [];
  104696. foreach (explode(',', $this->options['rules']) as $rule) {
  104697. $rule = trim($rule);
  104698. if ('' === $rule) {
  104699. throw new InvalidConfigurationException('Empty rule name is not allowed.');
  104700. }
  104701. if (str_starts_with($rule, '-')) {
  104702. $rules[substr($rule, 1)] = false;
  104703. } else {
  104704. $rules[$rule] = true;
  104705. }
  104706. }
  104707. return $rules;
  104708. }
  104709. private function validateRules(array $rules): void
  104710. {
  104711. $ruleSet = [];
  104712. foreach ($rules as $key => $value) {
  104713. if (\is_int($key)) {
  104714. throw new InvalidConfigurationException(\sprintf('Missing value for "%s" rule/set.', $value));
  104715. }
  104716. $ruleSet[$key] = true;
  104717. }
  104718. $ruleSet = new RuleSet($ruleSet);
  104719. $configuredFixers = array_keys($ruleSet->getRules());
  104720. $fixers = $this->createFixerFactory()->getFixers();
  104721. $availableFixers = array_map(static fn (FixerInterface $fixer): string => $fixer->getName(), $fixers);
  104722. $unknownFixers = array_diff($configuredFixers, $availableFixers);
  104723. if (\count($unknownFixers) > 0) {
  104724. $renamedRules = [
  104725. 'blank_line_before_return' => [
  104726. 'new_name' => 'blank_line_before_statement',
  104727. 'config' => ['statements' => ['return']],
  104728. ],
  104729. 'final_static_access' => [
  104730. 'new_name' => 'self_static_accessor',
  104731. ],
  104732. 'hash_to_slash_comment' => [
  104733. 'new_name' => 'single_line_comment_style',
  104734. 'config' => ['comment_types' => ['hash']],
  104735. ],
  104736. 'lowercase_constants' => [
  104737. 'new_name' => 'constant_case',
  104738. 'config' => ['case' => 'lower'],
  104739. ],
  104740. 'no_extra_consecutive_blank_lines' => [
  104741. 'new_name' => 'no_extra_blank_lines',
  104742. ],
  104743. 'no_multiline_whitespace_before_semicolons' => [
  104744. 'new_name' => 'multiline_whitespace_before_semicolons',
  104745. ],
  104746. 'no_short_echo_tag' => [
  104747. 'new_name' => 'echo_tag_syntax',
  104748. 'config' => ['format' => 'long'],
  104749. ],
  104750. 'php_unit_ordered_covers' => [
  104751. 'new_name' => 'phpdoc_order_by_value',
  104752. 'config' => ['annotations' => ['covers']],
  104753. ],
  104754. 'phpdoc_inline_tag' => [
  104755. 'new_name' => 'general_phpdoc_tag_rename, phpdoc_inline_tag_normalizer and phpdoc_tag_type',
  104756. ],
  104757. 'pre_increment' => [
  104758. 'new_name' => 'increment_style',
  104759. 'config' => ['style' => 'pre'],
  104760. ],
  104761. 'psr0' => [
  104762. 'new_name' => 'psr_autoloading',
  104763. 'config' => ['dir' => 'x'],
  104764. ],
  104765. 'psr4' => [
  104766. 'new_name' => 'psr_autoloading',
  104767. ],
  104768. 'silenced_deprecation_error' => [
  104769. 'new_name' => 'error_suppression',
  104770. ],
  104771. 'trailing_comma_in_multiline_array' => [
  104772. 'new_name' => 'trailing_comma_in_multiline',
  104773. 'config' => ['elements' => ['arrays']],
  104774. ],
  104775. ];
  104776. $message = 'The rules contain unknown fixers: ';
  104777. $hasOldRule = false;
  104778. foreach ($unknownFixers as $unknownFixer) {
  104779. if (isset($renamedRules[$unknownFixer])) {
  104780. $hasOldRule = true;
  104781. $message .= \sprintf(
  104782. '"%s" is renamed (did you mean "%s"?%s), ',
  104783. $unknownFixer,
  104784. $renamedRules[$unknownFixer]['new_name'],
  104785. isset($renamedRules[$unknownFixer]['config']) ? ' (note: use configuration "'.Utils::toString($renamedRules[$unknownFixer]['config']).'")' : ''
  104786. );
  104787. } else {
  104788. $matcher = new WordMatcher($availableFixers);
  104789. $alternative = $matcher->match($unknownFixer);
  104790. $message .= \sprintf(
  104791. '"%s"%s, ',
  104792. $unknownFixer,
  104793. null === $alternative ? '' : ' (did you mean "'.$alternative.'"?)'
  104794. );
  104795. }
  104796. }
  104797. $message = substr($message, 0, -2).'.';
  104798. if ($hasOldRule) {
  104799. $message .= "\nFor more info about updating see: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/v3.0.0/UPGRADE-v3.md#renamed-ruless.";
  104800. }
  104801. throw new InvalidConfigurationException($message);
  104802. }
  104803. foreach ($fixers as $fixer) {
  104804. $fixerName = $fixer->getName();
  104805. if (isset($rules[$fixerName]) && $fixer instanceof DeprecatedFixerInterface) {
  104806. $successors = $fixer->getSuccessorsNames();
  104807. $messageEnd = [] === $successors
  104808. ? \sprintf(' and will be removed in version %d.0.', Application::getMajorVersion() + 1)
  104809. : \sprintf('. Use %s instead.', str_replace('`', '"', Utils::naturalLanguageJoinWithBackticks($successors)));
  104810. Utils::triggerDeprecation(new \RuntimeException("Rule \"{$fixerName}\" is deprecated{$messageEnd}"));
  104811. }
  104812. }
  104813. }
  104814. private function resolveFinder(): iterable
  104815. {
  104816. $this->configFinderIsOverridden = false;
  104817. if ($this->isStdIn()) {
  104818. return new \ArrayIterator([new StdinFileInfo()]);
  104819. }
  104820. $modes = [self::PATH_MODE_OVERRIDE, self::PATH_MODE_INTERSECTION];
  104821. if (!\in_array(
  104822. $this->options['path-mode'],
  104823. $modes,
  104824. true
  104825. )) {
  104826. throw new InvalidConfigurationException(\sprintf(
  104827. 'The path-mode "%s" is not defined, supported are %s.',
  104828. $this->options['path-mode'],
  104829. Utils::naturalLanguageJoin($modes)
  104830. ));
  104831. }
  104832. $isIntersectionPathMode = self::PATH_MODE_INTERSECTION === $this->options['path-mode'];
  104833. $paths = array_map(
  104834. static fn (string $path) => realpath($path),
  104835. $this->getPath()
  104836. );
  104837. if (0 === \count($paths)) {
  104838. if ($isIntersectionPathMode) {
  104839. return new \ArrayIterator([]);
  104840. }
  104841. return $this->iterableToTraversable($this->getConfig()->getFinder());
  104842. }
  104843. $pathsByType = [
  104844. 'file' => [],
  104845. 'dir' => [],
  104846. ];
  104847. foreach ($paths as $path) {
  104848. if (is_file($path)) {
  104849. $pathsByType['file'][] = $path;
  104850. } else {
  104851. $pathsByType['dir'][] = $path.\DIRECTORY_SEPARATOR;
  104852. }
  104853. }
  104854. $nestedFinder = null;
  104855. $currentFinder = $this->iterableToTraversable($this->getConfig()->getFinder());
  104856. try {
  104857. $nestedFinder = $currentFinder instanceof \IteratorAggregate ? $currentFinder->getIterator() : $currentFinder;
  104858. } catch (\Exception $e) {
  104859. }
  104860. if ($isIntersectionPathMode) {
  104861. if (null === $nestedFinder) {
  104862. throw new InvalidConfigurationException(
  104863. 'Cannot create intersection with not-fully defined Finder in configuration file.'
  104864. );
  104865. }
  104866. return new \CallbackFilterIterator(
  104867. new \IteratorIterator($nestedFinder),
  104868. static function (\SplFileInfo $current) use ($pathsByType): bool {
  104869. $currentRealPath = $current->getRealPath();
  104870. if (\in_array($currentRealPath, $pathsByType['file'], true)) {
  104871. return true;
  104872. }
  104873. foreach ($pathsByType['dir'] as $path) {
  104874. if (str_starts_with($currentRealPath, $path)) {
  104875. return true;
  104876. }
  104877. }
  104878. return false;
  104879. }
  104880. );
  104881. }
  104882. if (null !== $this->getConfigFile() && null !== $nestedFinder) {
  104883. $this->configFinderIsOverridden = true;
  104884. }
  104885. if ($currentFinder instanceof SymfonyFinder && null === $nestedFinder) {
  104886. return $currentFinder->in($pathsByType['dir'])->append($pathsByType['file']);
  104887. }
  104888. return Finder::create()->in($pathsByType['dir'])->append($pathsByType['file']);
  104889. }
  104890. private function setOption(string $name, $value): void
  104891. {
  104892. if (!\array_key_exists($name, $this->options)) {
  104893. throw new InvalidConfigurationException(\sprintf('Unknown option name: "%s".', $name));
  104894. }
  104895. $this->options[$name] = $value;
  104896. }
  104897. private function resolveOptionBooleanValue(string $optionName): bool
  104898. {
  104899. $value = $this->options[$optionName];
  104900. if ('yes' === $value) {
  104901. return true;
  104902. }
  104903. if ('no' === $value) {
  104904. return false;
  104905. }
  104906. throw new InvalidConfigurationException(\sprintf('Expected "yes" or "no" for option "%s", got "%s".', $optionName, \is_object($value) ? \get_class($value) : (\is_scalar($value) ? $value : \gettype($value))));
  104907. }
  104908. private static function separatedContextLessInclude(string $path): ConfigInterface
  104909. {
  104910. $config = include $path;
  104911. if (!$config instanceof ConfigInterface) {
  104912. throw new InvalidConfigurationException(\sprintf('The config file: "%s" does not return a "PhpCsFixer\ConfigInterface" instance. Got: "%s".', $path, \is_object($config) ? \get_class($config) : \gettype($config)));
  104913. }
  104914. return $config;
  104915. }
  104916. private function isCachingAllowedForRuntime(): bool
  104917. {
  104918. return $this->toolInfo->isInstalledAsPhar()
  104919. || $this->toolInfo->isInstalledByComposer()
  104920. || $this->toolInfo->isRunInsideDocker()
  104921. || filter_var(getenv('PHP_CS_FIXER_ENFORCE_CACHE'), FILTER_VALIDATE_BOOL);
  104922. }
  104923. }
  104924. <?php
  104925. declare(strict_types=1);
  104926. namespace PhpCsFixer\Console\Report\ListSetsReport;
  104927. use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
  104928. /**
  104929. @readonly
  104930. */
  104931. final class ReportSummary
  104932. {
  104933. private array $sets;
  104934. public function __construct(array $sets)
  104935. {
  104936. $this->sets = $sets;
  104937. }
  104938. public function getSets(): array
  104939. {
  104940. return $this->sets;
  104941. }
  104942. }
  104943. <?php
  104944. declare(strict_types=1);
  104945. namespace PhpCsFixer\Console\Report\ListSetsReport;
  104946. use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
  104947. /**
  104948. @readonly
  104949. */
  104950. final class TextReporter implements ReporterInterface
  104951. {
  104952. public function getFormat(): string
  104953. {
  104954. return 'txt';
  104955. }
  104956. public function generate(ReportSummary $reportSummary): string
  104957. {
  104958. $sets = $reportSummary->getSets();
  104959. usort($sets, static fn (RuleSetDescriptionInterface $a, RuleSetDescriptionInterface $b): int => $a->getName() <=> $b->getName());
  104960. $output = '';
  104961. foreach ($sets as $i => $set) {
  104962. $output .= \sprintf('%2d) %s', $i + 1, $set->getName()).PHP_EOL.' '.$set->getDescription().PHP_EOL;
  104963. if ($set->isRisky()) {
  104964. $output .= ' Set contains risky rules.'.PHP_EOL;
  104965. }
  104966. }
  104967. return $output;
  104968. }
  104969. }
  104970. <?php
  104971. declare(strict_types=1);
  104972. namespace PhpCsFixer\Console\Report\ListSetsReport;
  104973. use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
  104974. /**
  104975. @readonly
  104976. */
  104977. final class JsonReporter implements ReporterInterface
  104978. {
  104979. public function getFormat(): string
  104980. {
  104981. return 'json';
  104982. }
  104983. public function generate(ReportSummary $reportSummary): string
  104984. {
  104985. $sets = $reportSummary->getSets();
  104986. usort($sets, static fn (RuleSetDescriptionInterface $a, RuleSetDescriptionInterface $b): int => $a->getName() <=> $b->getName());
  104987. $json = ['sets' => []];
  104988. foreach ($sets as $set) {
  104989. $setName = $set->getName();
  104990. $json['sets'][$setName] = [
  104991. 'description' => $set->getDescription(),
  104992. 'isRisky' => $set->isRisky(),
  104993. 'name' => $setName,
  104994. ];
  104995. }
  104996. return json_encode($json, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT);
  104997. }
  104998. }
  104999. <?php
  105000. declare(strict_types=1);
  105001. namespace PhpCsFixer\Console\Report\ListSetsReport;
  105002. use Symfony\Component\Finder\Finder as SymfonyFinder;
  105003. final class ReporterFactory
  105004. {
  105005. private array $reporters = [];
  105006. public function registerBuiltInReporters(): self
  105007. {
  105008. static $builtInReporters;
  105009. if (null === $builtInReporters) {
  105010. $builtInReporters = [];
  105011. foreach (SymfonyFinder::create()->files()->name('*Reporter.php')->in(__DIR__) as $file) {
  105012. $relativeNamespace = $file->getRelativePath();
  105013. $builtInReporters[] = \sprintf(
  105014. '%s\%s%s',
  105015. __NAMESPACE__,
  105016. '' !== $relativeNamespace ? $relativeNamespace.'\\' : '',
  105017. $file->getBasename('.php')
  105018. );
  105019. }
  105020. }
  105021. foreach ($builtInReporters as $reporterClass) {
  105022. $this->registerReporter(new $reporterClass());
  105023. }
  105024. return $this;
  105025. }
  105026. public function registerReporter(ReporterInterface $reporter): self
  105027. {
  105028. $format = $reporter->getFormat();
  105029. if (isset($this->reporters[$format])) {
  105030. throw new \UnexpectedValueException(\sprintf('Reporter for format "%s" is already registered.', $format));
  105031. }
  105032. $this->reporters[$format] = $reporter;
  105033. return $this;
  105034. }
  105035. public function getFormats(): array
  105036. {
  105037. $formats = array_keys($this->reporters);
  105038. sort($formats);
  105039. return $formats;
  105040. }
  105041. public function getReporter(string $format): ReporterInterface
  105042. {
  105043. if (!isset($this->reporters[$format])) {
  105044. throw new \UnexpectedValueException(\sprintf('Reporter for format "%s" is not registered.', $format));
  105045. }
  105046. return $this->reporters[$format];
  105047. }
  105048. }
  105049. <?php
  105050. declare(strict_types=1);
  105051. namespace PhpCsFixer\Console\Report\ListSetsReport;
  105052. interface ReporterInterface
  105053. {
  105054. public function getFormat(): string;
  105055. public function generate(ReportSummary $reportSummary): string;
  105056. }
  105057. <?php
  105058. declare(strict_types=1);
  105059. namespace PhpCsFixer\Console\Report\FixReport;
  105060. use PhpCsFixer\Console\Application;
  105061. use PhpCsFixer\Preg;
  105062. use Symfony\Component\Console\Formatter\OutputFormatter;
  105063. /**
  105064. @readonly
  105065. */
  105066. final class JunitReporter implements ReporterInterface
  105067. {
  105068. public function getFormat(): string
  105069. {
  105070. return 'junit';
  105071. }
  105072. public function generate(ReportSummary $reportSummary): string
  105073. {
  105074. if (!\extension_loaded('dom')) {
  105075. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  105076. }
  105077. $dom = new \DOMDocument('1.0', 'UTF-8');
  105078. $testsuites = $dom->appendChild($dom->createElement('testsuites'));
  105079. $testsuite = $testsuites->appendChild($dom->createElement('testsuite'));
  105080. $testsuite->setAttribute('name', 'PHP CS Fixer');
  105081. $properties = $dom->createElement('properties');
  105082. $property = $dom->createElement('property');
  105083. $property->setAttribute('name', 'about');
  105084. $property->setAttribute('value', Application::getAbout());
  105085. $properties->appendChild($property);
  105086. $testsuite->appendChild($properties);
  105087. if (\count($reportSummary->getChanged()) > 0) {
  105088. $this->createFailedTestCases($dom, $testsuite, $reportSummary);
  105089. } else {
  105090. $this->createSuccessTestCase($dom, $testsuite);
  105091. }
  105092. if ($reportSummary->getTime() > 0) {
  105093. $testsuite->setAttribute(
  105094. 'time',
  105095. \sprintf(
  105096. '%.3f',
  105097. $reportSummary->getTime() / 1_000
  105098. )
  105099. );
  105100. }
  105101. $dom->formatOutput = true;
  105102. $result = $dom->saveXML();
  105103. if (false === $result) {
  105104. throw new \RuntimeException('Failed to generate XML output');
  105105. }
  105106. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($result) : $result;
  105107. }
  105108. private function createSuccessTestCase(\DOMDocument $dom, \DOMElement $testsuite): void
  105109. {
  105110. $testcase = $dom->createElement('testcase');
  105111. $testcase->setAttribute('name', 'All OK');
  105112. $testcase->setAttribute('assertions', '1');
  105113. $testsuite->appendChild($testcase);
  105114. $testsuite->setAttribute('tests', '1');
  105115. $testsuite->setAttribute('assertions', '1');
  105116. $testsuite->setAttribute('failures', '0');
  105117. $testsuite->setAttribute('errors', '0');
  105118. }
  105119. private function createFailedTestCases(\DOMDocument $dom, \DOMElement $testsuite, ReportSummary $reportSummary): void
  105120. {
  105121. $assertionsCount = 0;
  105122. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  105123. $testcase = $this->createFailedTestCase(
  105124. $dom,
  105125. $file,
  105126. $fixResult,
  105127. $reportSummary->shouldAddAppliedFixers()
  105128. );
  105129. $testsuite->appendChild($testcase);
  105130. $assertionsCount += (int) $testcase->getAttribute('assertions');
  105131. }
  105132. $testsuite->setAttribute('tests', (string) \count($reportSummary->getChanged()));
  105133. $testsuite->setAttribute('assertions', (string) $assertionsCount);
  105134. $testsuite->setAttribute('failures', (string) $assertionsCount);
  105135. $testsuite->setAttribute('errors', '0');
  105136. }
  105137. private function createFailedTestCase(\DOMDocument $dom, string $file, array $fixResult, bool $shouldAddAppliedFixers): \DOMElement
  105138. {
  105139. $appliedFixersCount = \count($fixResult['appliedFixers']);
  105140. $testName = str_replace('.', '_DOT_', Preg::replace('@\.'.pathinfo($file, PATHINFO_EXTENSION).'$@', '', $file));
  105141. $testcase = $dom->createElement('testcase');
  105142. $testcase->setAttribute('name', $testName);
  105143. $testcase->setAttribute('file', $file);
  105144. $testcase->setAttribute('assertions', (string) $appliedFixersCount);
  105145. $failure = $dom->createElement('failure');
  105146. $failure->setAttribute('type', 'code_style');
  105147. $testcase->appendChild($failure);
  105148. if ($shouldAddAppliedFixers) {
  105149. $failureContent = "applied fixers:\n---------------\n";
  105150. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  105151. $failureContent .= "* {$appliedFixer}\n";
  105152. }
  105153. } else {
  105154. $failureContent = "Wrong code style\n";
  105155. }
  105156. if ('' !== $fixResult['diff']) {
  105157. $failureContent .= "\nDiff:\n---------------\n\n".$fixResult['diff'];
  105158. }
  105159. $failure->appendChild($dom->createCDATASection(trim($failureContent)));
  105160. return $testcase;
  105161. }
  105162. }
  105163. <?php
  105164. declare(strict_types=1);
  105165. namespace PhpCsFixer\Console\Report\FixReport;
  105166. use PhpCsFixer\Console\Application;
  105167. use Symfony\Component\Console\Formatter\OutputFormatter;
  105168. /**
  105169. @readonly
  105170. */
  105171. final class XmlReporter implements ReporterInterface
  105172. {
  105173. public function getFormat(): string
  105174. {
  105175. return 'xml';
  105176. }
  105177. public function generate(ReportSummary $reportSummary): string
  105178. {
  105179. if (!\extension_loaded('dom')) {
  105180. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  105181. }
  105182. $dom = new \DOMDocument('1.0', 'UTF-8');
  105183. $root = $dom->createElement('report');
  105184. $dom->appendChild($root);
  105185. $root->appendChild($this->createAboutElement($dom, Application::getAbout()));
  105186. $filesXML = $dom->createElement('files');
  105187. $root->appendChild($filesXML);
  105188. $i = 1;
  105189. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  105190. $fileXML = $dom->createElement('file');
  105191. $fileXML->setAttribute('id', (string) $i++);
  105192. $fileXML->setAttribute('name', $file);
  105193. $filesXML->appendChild($fileXML);
  105194. if ($reportSummary->shouldAddAppliedFixers()) {
  105195. $fileXML->appendChild(
  105196. $this->createAppliedFixersElement($dom, $fixResult['appliedFixers']),
  105197. );
  105198. }
  105199. if ('' !== $fixResult['diff']) {
  105200. $fileXML->appendChild($this->createDiffElement($dom, $fixResult['diff']));
  105201. }
  105202. }
  105203. if (0 !== $reportSummary->getTime()) {
  105204. $root->appendChild($this->createTimeElement($reportSummary->getTime(), $dom));
  105205. }
  105206. if (0 !== $reportSummary->getMemory()) {
  105207. $root->appendChild($this->createMemoryElement($reportSummary->getMemory(), $dom));
  105208. }
  105209. $dom->formatOutput = true;
  105210. $result = $dom->saveXML();
  105211. if (false === $result) {
  105212. throw new \RuntimeException('Failed to generate XML output');
  105213. }
  105214. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($result) : $result;
  105215. }
  105216. private function createAppliedFixersElement(\DOMDocument $dom, array $appliedFixers): \DOMElement
  105217. {
  105218. $appliedFixersXML = $dom->createElement('applied_fixers');
  105219. foreach ($appliedFixers as $appliedFixer) {
  105220. $appliedFixerXML = $dom->createElement('applied_fixer');
  105221. $appliedFixerXML->setAttribute('name', $appliedFixer);
  105222. $appliedFixersXML->appendChild($appliedFixerXML);
  105223. }
  105224. return $appliedFixersXML;
  105225. }
  105226. private function createDiffElement(\DOMDocument $dom, string $diff): \DOMElement
  105227. {
  105228. $diffXML = $dom->createElement('diff');
  105229. $diffXML->appendChild($dom->createCDATASection($diff));
  105230. return $diffXML;
  105231. }
  105232. private function createTimeElement(float $time, \DOMDocument $dom): \DOMElement
  105233. {
  105234. $time = round($time / 1_000, 3);
  105235. $timeXML = $dom->createElement('time');
  105236. $timeXML->setAttribute('unit', 's');
  105237. $timeTotalXML = $dom->createElement('total');
  105238. $timeTotalXML->setAttribute('value', (string) $time);
  105239. $timeXML->appendChild($timeTotalXML);
  105240. return $timeXML;
  105241. }
  105242. private function createMemoryElement(float $memory, \DOMDocument $dom): \DOMElement
  105243. {
  105244. $memory = round($memory / 1_024 / 1_024, 3);
  105245. $memoryXML = $dom->createElement('memory');
  105246. $memoryXML->setAttribute('value', (string) $memory);
  105247. $memoryXML->setAttribute('unit', 'MB');
  105248. return $memoryXML;
  105249. }
  105250. private function createAboutElement(\DOMDocument $dom, string $about): \DOMElement
  105251. {
  105252. $xml = $dom->createElement('about');
  105253. $xml->setAttribute('value', $about);
  105254. return $xml;
  105255. }
  105256. }
  105257. <?php
  105258. declare(strict_types=1);
  105259. namespace PhpCsFixer\Console\Report\FixReport;
  105260. /**
  105261. @readonly
  105262. */
  105263. final class ReportSummary
  105264. {
  105265. private array $changed;
  105266. private int $filesCount;
  105267. private int $time;
  105268. private int $memory;
  105269. private bool $addAppliedFixers;
  105270. private bool $isDryRun;
  105271. private bool $isDecoratedOutput;
  105272. public function __construct(
  105273. array $changed,
  105274. int $filesCount,
  105275. int $time,
  105276. int $memory,
  105277. bool $addAppliedFixers,
  105278. bool $isDryRun,
  105279. bool $isDecoratedOutput
  105280. ) {
  105281. $this->changed = $changed;
  105282. $this->filesCount = $filesCount;
  105283. $this->time = $time;
  105284. $this->memory = $memory;
  105285. $this->addAppliedFixers = $addAppliedFixers;
  105286. $this->isDryRun = $isDryRun;
  105287. $this->isDecoratedOutput = $isDecoratedOutput;
  105288. }
  105289. public function isDecoratedOutput(): bool
  105290. {
  105291. return $this->isDecoratedOutput;
  105292. }
  105293. public function isDryRun(): bool
  105294. {
  105295. return $this->isDryRun;
  105296. }
  105297. public function getChanged(): array
  105298. {
  105299. return $this->changed;
  105300. }
  105301. public function getMemory(): int
  105302. {
  105303. return $this->memory;
  105304. }
  105305. public function getTime(): int
  105306. {
  105307. return $this->time;
  105308. }
  105309. public function getFilesCount(): int
  105310. {
  105311. return $this->filesCount;
  105312. }
  105313. public function shouldAddAppliedFixers(): bool
  105314. {
  105315. return $this->addAppliedFixers;
  105316. }
  105317. }
  105318. <?php
  105319. declare(strict_types=1);
  105320. namespace PhpCsFixer\Console\Report\FixReport;
  105321. use PhpCsFixer\Console\Application;
  105322. use SebastianBergmann\Diff\Chunk;
  105323. use SebastianBergmann\Diff\Diff;
  105324. use SebastianBergmann\Diff\Parser;
  105325. use Symfony\Component\Console\Formatter\OutputFormatter;
  105326. /**
  105327. @readonly
  105328. */
  105329. final class GitlabReporter implements ReporterInterface
  105330. {
  105331. private Parser $diffParser;
  105332. public function __construct()
  105333. {
  105334. $this->diffParser = new Parser();
  105335. }
  105336. public function getFormat(): string
  105337. {
  105338. return 'gitlab';
  105339. }
  105340. public function generate(ReportSummary $reportSummary): string
  105341. {
  105342. $about = Application::getAbout();
  105343. $report = [];
  105344. foreach ($reportSummary->getChanged() as $fileName => $change) {
  105345. foreach ($change['appliedFixers'] as $fixerName) {
  105346. $report[] = [
  105347. 'check_name' => 'PHP-CS-Fixer.'.$fixerName,
  105348. 'description' => 'PHP-CS-Fixer.'.$fixerName.' by '.$about,
  105349. 'categories' => ['Style'],
  105350. 'fingerprint' => md5($fileName.$fixerName),
  105351. 'severity' => 'minor',
  105352. 'location' => [
  105353. 'path' => $fileName,
  105354. 'lines' => self::getLines($this->diffParser->parse($change['diff'])),
  105355. ],
  105356. ];
  105357. }
  105358. }
  105359. $jsonString = json_encode($report, JSON_THROW_ON_ERROR);
  105360. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($jsonString) : $jsonString;
  105361. }
  105362. private static function getLines(array $diffs): array
  105363. {
  105364. if (isset($diffs[0])) {
  105365. $firstDiff = $diffs[0];
  105366. $firstChunk = \Closure::bind(static fn (Diff $diff) => array_shift($diff->chunks), null, $firstDiff)($firstDiff);
  105367. if ($firstChunk instanceof Chunk) {
  105368. return \Closure::bind(static fn (Chunk $chunk): array => ['begin' => $chunk->start, 'end' => $chunk->startRange], null, $firstChunk)($firstChunk);
  105369. }
  105370. }
  105371. return ['begin' => 0, 'end' => 0];
  105372. }
  105373. }
  105374. <?php
  105375. declare(strict_types=1);
  105376. namespace PhpCsFixer\Console\Report\FixReport;
  105377. use PhpCsFixer\Console\Application;
  105378. use Symfony\Component\Console\Formatter\OutputFormatter;
  105379. /**
  105380. @readonly
  105381. */
  105382. final class CheckstyleReporter implements ReporterInterface
  105383. {
  105384. public function getFormat(): string
  105385. {
  105386. return 'checkstyle';
  105387. }
  105388. public function generate(ReportSummary $reportSummary): string
  105389. {
  105390. if (!\extension_loaded('dom')) {
  105391. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  105392. }
  105393. $dom = new \DOMDocument('1.0', 'UTF-8');
  105394. $checkstyles = $dom->appendChild($dom->createElement('checkstyle'));
  105395. $checkstyles->setAttribute('version', Application::getAbout());
  105396. foreach ($reportSummary->getChanged() as $filePath => $fixResult) {
  105397. $file = $checkstyles->appendChild($dom->createElement('file'));
  105398. $file->setAttribute('name', $filePath);
  105399. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  105400. $error = $this->createError($dom, $appliedFixer);
  105401. $file->appendChild($error);
  105402. }
  105403. }
  105404. $dom->formatOutput = true;
  105405. $result = $dom->saveXML();
  105406. if (false === $result) {
  105407. throw new \RuntimeException('Failed to generate XML output');
  105408. }
  105409. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($result) : $result;
  105410. }
  105411. private function createError(\DOMDocument $dom, string $appliedFixer): \DOMElement
  105412. {
  105413. $error = $dom->createElement('error');
  105414. $error->setAttribute('severity', 'warning');
  105415. $error->setAttribute('source', 'PHP-CS-Fixer.'.$appliedFixer);
  105416. $error->setAttribute('message', 'Found violation(s) of type: '.$appliedFixer);
  105417. return $error;
  105418. }
  105419. }
  105420. <?php
  105421. declare(strict_types=1);
  105422. namespace PhpCsFixer\Console\Report\FixReport;
  105423. use PhpCsFixer\Differ\DiffConsoleFormatter;
  105424. /**
  105425. @readonly
  105426. */
  105427. final class TextReporter implements ReporterInterface
  105428. {
  105429. public function getFormat(): string
  105430. {
  105431. return 'txt';
  105432. }
  105433. public function generate(ReportSummary $reportSummary): string
  105434. {
  105435. $output = '';
  105436. $identifiedFiles = 0;
  105437. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  105438. ++$identifiedFiles;
  105439. $output .= \sprintf('%4d) %s', $identifiedFiles, $file);
  105440. if ($reportSummary->shouldAddAppliedFixers()) {
  105441. $output .= $this->getAppliedFixers(
  105442. $reportSummary->isDecoratedOutput(),
  105443. $fixResult['appliedFixers'],
  105444. );
  105445. }
  105446. $output .= $this->getDiff($reportSummary->isDecoratedOutput(), $fixResult['diff']);
  105447. $output .= PHP_EOL;
  105448. }
  105449. return $output.$this->getFooter(
  105450. $reportSummary->getTime(),
  105451. $identifiedFiles,
  105452. $reportSummary->getFilesCount(),
  105453. $reportSummary->getMemory(),
  105454. $reportSummary->isDryRun()
  105455. );
  105456. }
  105457. private function getAppliedFixers(bool $isDecoratedOutput, array $appliedFixers): string
  105458. {
  105459. return \sprintf(
  105460. $isDecoratedOutput ? ' (<comment>%s</comment>)' : ' (%s)',
  105461. implode(', ', $appliedFixers)
  105462. );
  105463. }
  105464. private function getDiff(bool $isDecoratedOutput, string $diff): string
  105465. {
  105466. if ('' === $diff) {
  105467. return '';
  105468. }
  105469. $diffFormatter = new DiffConsoleFormatter($isDecoratedOutput, \sprintf(
  105470. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  105471. PHP_EOL,
  105472. PHP_EOL
  105473. ));
  105474. return PHP_EOL.$diffFormatter->format($diff).PHP_EOL;
  105475. }
  105476. private function getFooter(int $time, int $identifiedFiles, int $files, int $memory, bool $isDryRun): string
  105477. {
  105478. if (0 === $time || 0 === $memory) {
  105479. return '';
  105480. }
  105481. return PHP_EOL.\sprintf(
  105482. '%s %d of %d %s in %.3f seconds, %.2f MB memory used'.PHP_EOL,
  105483. $isDryRun ? 'Found' : 'Fixed',
  105484. $identifiedFiles,
  105485. $files,
  105486. $isDryRun ? 'files that can be fixed' : 'files',
  105487. $time / 1_000,
  105488. $memory / 1_024 / 1_024
  105489. );
  105490. }
  105491. }
  105492. <?php
  105493. declare(strict_types=1);
  105494. namespace PhpCsFixer\Console\Report\FixReport;
  105495. use PhpCsFixer\Console\Application;
  105496. use Symfony\Component\Console\Formatter\OutputFormatter;
  105497. /**
  105498. @readonly
  105499. */
  105500. final class JsonReporter implements ReporterInterface
  105501. {
  105502. public function getFormat(): string
  105503. {
  105504. return 'json';
  105505. }
  105506. public function generate(ReportSummary $reportSummary): string
  105507. {
  105508. $jsonFiles = [];
  105509. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  105510. $jsonFile = ['name' => $file];
  105511. if ($reportSummary->shouldAddAppliedFixers()) {
  105512. $jsonFile['appliedFixers'] = $fixResult['appliedFixers'];
  105513. }
  105514. if ('' !== $fixResult['diff']) {
  105515. $jsonFile['diff'] = $fixResult['diff'];
  105516. }
  105517. $jsonFiles[] = $jsonFile;
  105518. }
  105519. $json = [
  105520. 'about' => Application::getAbout(),
  105521. 'files' => $jsonFiles,
  105522. 'time' => [
  105523. 'total' => round($reportSummary->getTime() / 1_000, 3),
  105524. ],
  105525. 'memory' => round($reportSummary->getMemory() / 1_024 / 1_024, 3),
  105526. ];
  105527. $json = json_encode($json, JSON_THROW_ON_ERROR);
  105528. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($json) : $json;
  105529. }
  105530. }
  105531. <?php
  105532. declare(strict_types=1);
  105533. namespace PhpCsFixer\Console\Report\FixReport;
  105534. use Symfony\Component\Finder\Finder as SymfonyFinder;
  105535. final class ReporterFactory
  105536. {
  105537. private array $reporters = [];
  105538. public function registerBuiltInReporters(): self
  105539. {
  105540. static $builtInReporters;
  105541. if (null === $builtInReporters) {
  105542. $builtInReporters = [];
  105543. foreach (SymfonyFinder::create()->files()->name('*Reporter.php')->in(__DIR__) as $file) {
  105544. $relativeNamespace = $file->getRelativePath();
  105545. $builtInReporters[] = \sprintf(
  105546. '%s\%s%s',
  105547. __NAMESPACE__,
  105548. '' !== $relativeNamespace ? $relativeNamespace.'\\' : '',
  105549. $file->getBasename('.php')
  105550. );
  105551. }
  105552. }
  105553. foreach ($builtInReporters as $reporterClass) {
  105554. $this->registerReporter(new $reporterClass());
  105555. }
  105556. return $this;
  105557. }
  105558. public function registerReporter(ReporterInterface $reporter): self
  105559. {
  105560. $format = $reporter->getFormat();
  105561. if (isset($this->reporters[$format])) {
  105562. throw new \UnexpectedValueException(\sprintf('Reporter for format "%s" is already registered.', $format));
  105563. }
  105564. $this->reporters[$format] = $reporter;
  105565. return $this;
  105566. }
  105567. public function getFormats(): array
  105568. {
  105569. $formats = array_keys($this->reporters);
  105570. sort($formats);
  105571. return $formats;
  105572. }
  105573. public function getReporter(string $format): ReporterInterface
  105574. {
  105575. if (!isset($this->reporters[$format])) {
  105576. throw new \UnexpectedValueException(\sprintf('Reporter for format "%s" is not registered.', $format));
  105577. }
  105578. return $this->reporters[$format];
  105579. }
  105580. }
  105581. <?php
  105582. declare(strict_types=1);
  105583. namespace PhpCsFixer\Console\Report\FixReport;
  105584. interface ReporterInterface
  105585. {
  105586. public function getFormat(): string;
  105587. public function generate(ReportSummary $reportSummary): string;
  105588. }
  105589. <?php
  105590. declare(strict_types=1);
  105591. namespace PhpCsFixer\Console\Command;
  105592. final class DescribeNameNotFoundException extends \InvalidArgumentException
  105593. {
  105594. private string $name;
  105595. private string $type;
  105596. public function __construct(string $name, string $type)
  105597. {
  105598. $this->name = $name;
  105599. $this->type = $type;
  105600. parent::__construct();
  105601. }
  105602. public function getName(): string
  105603. {
  105604. return $this->name;
  105605. }
  105606. public function getType(): string
  105607. {
  105608. return $this->type;
  105609. }
  105610. }
  105611. <?php
  105612. declare(strict_types=1);
  105613. namespace PhpCsFixer\Console\Command;
  105614. use PhpCsFixer\ToolInfoInterface;
  105615. use Symfony\Component\Console\Attribute\AsCommand;
  105616. use Symfony\Component\Console\Input\InputInterface;
  105617. use Symfony\Component\Console\Input\InputOption;
  105618. #[AsCommand(name: 'check', description: 'Checks if configured files/directories comply with configured rules.')]
  105619. final class CheckCommand extends FixCommand
  105620. {
  105621. protected static $defaultName = 'check';
  105622. protected static $defaultDescription = 'Checks if configured files/directories comply with configured rules.';
  105623. public function __construct(ToolInfoInterface $toolInfo)
  105624. {
  105625. parent::__construct($toolInfo);
  105626. }
  105627. public function getHelp(): string
  105628. {
  105629. $help = explode('<comment>--dry-run</comment>', parent::getHelp());
  105630. return substr($help[0], 0, strrpos($help[0], "\n") - 1)
  105631. .substr($help[1], strpos($help[1], "\n"));
  105632. }
  105633. protected function configure(): void
  105634. {
  105635. parent::configure();
  105636. $this->setDefinition([
  105637. ...array_values($this->getDefinition()->getArguments()),
  105638. ...array_values(array_filter(
  105639. $this->getDefinition()->getOptions(),
  105640. static fn (InputOption $option): bool => 'dry-run' !== $option->getName()
  105641. )),
  105642. ]);
  105643. }
  105644. protected function isDryRun(InputInterface $input): bool
  105645. {
  105646. return true;
  105647. }
  105648. }
  105649. <?php
  105650. declare(strict_types=1);
  105651. namespace PhpCsFixer\Console\Command;
  105652. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  105653. use PhpCsFixer\FixerConfiguration\FixerOptionInterface;
  105654. use PhpCsFixer\Utils;
  105655. use Symfony\Component\Console\Attribute\AsCommand;
  105656. use Symfony\Component\Console\Command\HelpCommand as BaseHelpCommand;
  105657. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  105658. use Symfony\Component\Console\Input\InputInterface;
  105659. use Symfony\Component\Console\Output\OutputInterface;
  105660. #[AsCommand(name: 'help')]
  105661. final class HelpCommand extends BaseHelpCommand
  105662. {
  105663. protected static $defaultName = 'help';
  105664. public static function getDisplayableAllowedValues(FixerOptionInterface $option): ?array
  105665. {
  105666. $allowed = $option->getAllowedValues();
  105667. if (null !== $allowed) {
  105668. $allowed = array_filter($allowed, static fn ($value): bool => !$value instanceof \Closure);
  105669. usort($allowed, static function ($valueA, $valueB): int {
  105670. if ($valueA instanceof AllowedValueSubset) {
  105671. return -1;
  105672. }
  105673. if ($valueB instanceof AllowedValueSubset) {
  105674. return 1;
  105675. }
  105676. return strcasecmp(
  105677. Utils::toString($valueA),
  105678. Utils::toString($valueB)
  105679. );
  105680. });
  105681. if (0 === \count($allowed)) {
  105682. $allowed = null;
  105683. }
  105684. }
  105685. return $allowed;
  105686. }
  105687. protected function initialize(InputInterface $input, OutputInterface $output): void
  105688. {
  105689. $output->getFormatter()->setStyle('url', new OutputFormatterStyle('blue'));
  105690. }
  105691. }
  105692. <?php
  105693. declare(strict_types=1);
  105694. namespace PhpCsFixer\Console\Command;
  105695. final class FixCommandExitStatusCalculator
  105696. {
  105697. public const EXIT_STATUS_FLAG_HAS_INVALID_FILES = 4;
  105698. public const EXIT_STATUS_FLAG_HAS_CHANGED_FILES = 8;
  105699. public const EXIT_STATUS_FLAG_HAS_INVALID_CONFIG = 16;
  105700. public const EXIT_STATUS_FLAG_HAS_INVALID_FIXER_CONFIG = 32;
  105701. public const EXIT_STATUS_FLAG_EXCEPTION_IN_APP = 64;
  105702. public function calculate(
  105703. bool $isDryRun,
  105704. bool $hasChangedFiles,
  105705. bool $hasInvalidErrors,
  105706. bool $hasExceptionErrors,
  105707. bool $hasLintErrorsAfterFixing
  105708. ): int {
  105709. $exitStatus = 0;
  105710. if ($isDryRun) {
  105711. if ($hasChangedFiles) {
  105712. $exitStatus |= self::EXIT_STATUS_FLAG_HAS_CHANGED_FILES;
  105713. }
  105714. if ($hasInvalidErrors) {
  105715. $exitStatus |= self::EXIT_STATUS_FLAG_HAS_INVALID_FILES;
  105716. }
  105717. }
  105718. if ($hasExceptionErrors || $hasLintErrorsAfterFixing) {
  105719. $exitStatus |= self::EXIT_STATUS_FLAG_EXCEPTION_IN_APP;
  105720. }
  105721. return $exitStatus;
  105722. }
  105723. }
  105724. <?php
  105725. declare(strict_types=1);
  105726. namespace PhpCsFixer\Console\Command;
  105727. use PhpCsFixer\Config;
  105728. use PhpCsFixer\ConfigInterface;
  105729. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  105730. use PhpCsFixer\Console\Application;
  105731. use PhpCsFixer\Console\ConfigurationResolver;
  105732. use PhpCsFixer\Console\Output\ErrorOutput;
  105733. use PhpCsFixer\Console\Output\OutputContext;
  105734. use PhpCsFixer\Console\Output\Progress\ProgressOutputFactory;
  105735. use PhpCsFixer\Console\Output\Progress\ProgressOutputType;
  105736. use PhpCsFixer\Console\Report\FixReport\ReportSummary;
  105737. use PhpCsFixer\Error\ErrorsManager;
  105738. use PhpCsFixer\Runner\Event\FileProcessed;
  105739. use PhpCsFixer\Runner\Runner;
  105740. use PhpCsFixer\ToolInfoInterface;
  105741. use Symfony\Component\Console\Attribute\AsCommand;
  105742. use Symfony\Component\Console\Command\Command;
  105743. use Symfony\Component\Console\Formatter\OutputFormatter;
  105744. use Symfony\Component\Console\Input\InputArgument;
  105745. use Symfony\Component\Console\Input\InputInterface;
  105746. use Symfony\Component\Console\Input\InputOption;
  105747. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  105748. use Symfony\Component\Console\Output\OutputInterface;
  105749. use Symfony\Component\Console\Terminal;
  105750. use Symfony\Component\EventDispatcher\EventDispatcher;
  105751. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  105752. use Symfony\Component\Stopwatch\Stopwatch;
  105753. #[AsCommand(name: 'fix', description: 'Fixes a directory or a file.')]
  105754. class FixCommand extends Command
  105755. {
  105756. protected static $defaultName = 'fix';
  105757. protected static $defaultDescription = 'Fixes a directory or a file.';
  105758. private EventDispatcherInterface $eventDispatcher;
  105759. private ErrorsManager $errorsManager;
  105760. private Stopwatch $stopwatch;
  105761. private ConfigInterface $defaultConfig;
  105762. private ToolInfoInterface $toolInfo;
  105763. private ProgressOutputFactory $progressOutputFactory;
  105764. public function __construct(ToolInfoInterface $toolInfo)
  105765. {
  105766. parent::__construct();
  105767. $this->eventDispatcher = new EventDispatcher();
  105768. $this->errorsManager = new ErrorsManager();
  105769. $this->stopwatch = new Stopwatch();
  105770. $this->defaultConfig = new Config();
  105771. $this->toolInfo = $toolInfo;
  105772. $this->progressOutputFactory = new ProgressOutputFactory();
  105773. }
  105774. public function getHelp(): string
  105775. {
  105776. return <<<'EOF'
  105777. The <info>%command.name%</info> command tries to %command.name% as much coding standards
  105778. problems as possible on a given file or files in a given directory and its subdirectories:
  105779. <info>$ php %command.full_name% /path/to/dir</info>
  105780. <info>$ php %command.full_name% /path/to/file</info>
  105781. By default <comment>--path-mode</comment> is set to `override`, which means, that if you specify the path to a file or a directory via
  105782. command arguments, then the paths provided to a `Finder` in config file will be ignored. You can use <comment>--path-mode=intersection</comment>
  105783. to merge paths from the config file and from the argument:
  105784. <info>$ php %command.full_name% --path-mode=intersection /path/to/dir</info>
  105785. The <comment>--format</comment> option for the output format. Supported formats are `@auto` (default one on v4+), `txt` (default one on v3), `json`, `xml`, `checkstyle`, `junit` and `gitlab`.
  105786. * `@auto` aims to auto-select best reporter for given CI or local execution (resolution into best format is outside of BC promise and is future-ready)
  105787. * `gitlab` for GitLab
  105788. * `@auto,{format}` takes `@auto` under CI, and {format} otherwise
  105789. NOTE: the output for the following formats are generated in accordance with schemas
  105790. * `checkstyle` follows the common `"checkstyle" XML schema </doc/schemas/fix/checkstyle.xsd>`_
  105791. * `gitlab` follows the `codeclimate JSON schema </doc/schemas/fix/codeclimate.json>`_
  105792. * `json` follows the `own JSON schema </doc/schemas/fix/schema.json>`_
  105793. * `junit` follows the `JUnit XML schema from Jenkins </doc/schemas/fix/junit-10.xsd>`_
  105794. * `xml` follows the `own XML schema </doc/schemas/fix/xml.xsd>`_
  105795. The <comment>--quiet</comment> Do not output any message.
  105796. The <comment>--verbose</comment> option will show the applied rules. When using the `txt` format it will also display progress notifications.
  105797. NOTE: if there is an error like "errors reported during linting after fixing", you can use this to be even more verbose for debugging purpose
  105798. * `-v`: verbose
  105799. * `-vv`: very verbose
  105800. * `-vvv`: debug
  105801. The <comment>--rules</comment> option limits the rules to apply to the
  105802. project:
  105803. EOF. <<<'EOF'
  105804. <info>$ php %command.full_name% /path/to/project --rules=@PSR12</info>
  105805. By default the PSR-12 rules are used.
  105806. The <comment>--rules</comment> option lets you choose the exact rules to
  105807. apply (the rule names must be separated by a comma):
  105808. <info>$ php %command.full_name% /path/to/dir --rules=line_ending,full_opening_tag,indentation_type</info>
  105809. You can also exclude the rules you don't want by placing a dash in front of the rule name, if this is more convenient,
  105810. using <comment>-name_of_fixer</comment>:
  105811. <info>$ php %command.full_name% /path/to/dir --rules=-full_opening_tag,-indentation_type</info>
  105812. When using combinations of exact and exclude rules, applying exact rules along with above excluded results:
  105813. <info>$ php %command.full_name% /path/to/project --rules=@Symfony,-@PSR1,-blank_line_before_statement,strict_comparison</info>
  105814. Complete configuration for rules can be supplied using a `json` formatted string.
  105815. <info>$ php %command.full_name% /path/to/project --rules='{"concat_space": {"spacing": "none"}}'</info>
  105816. The <comment>--dry-run</comment> flag will run the fixer without making changes to your files.
  105817. The <comment>--sequential</comment> flag will enforce sequential analysis even if parallel config is provided.
  105818. The <comment>--diff</comment> flag can be used to let the fixer output all the changes it makes.
  105819. The <comment>--allow-risky</comment> option (pass `yes` or `no`) allows you to set whether risky rules may run. Default value is taken from config file.
  105820. A rule is considered risky if it could change code behaviour. By default no risky rules are run.
  105821. The <comment>--stop-on-violation</comment> flag stops the execution upon first file that needs to be fixed.
  105822. The <comment>--show-progress</comment> option allows you to choose the way process progress is rendered:
  105823. * <comment>none</comment>: disables progress output;
  105824. * <comment>dots</comment>: multiline progress output with number of files and percentage on each line.
  105825. * <comment>bar</comment>: single line progress output with number of files and calculated percentage.
  105826. If the option is not provided, it defaults to <comment>bar</comment> unless a config file that disables output is used, in which case it defaults to <comment>none</comment>. This option has no effect if the verbosity of the command is less than <comment>verbose</comment>.
  105827. <info>$ php %command.full_name% --verbose --show-progress=dots</info>
  105828. By using <comment>--using-cache</comment> option with `yes` or `no` you can set if the caching
  105829. mechanism should be used.
  105830. The command can also read from standard input, in which case it won't
  105831. automatically fix anything:
  105832. <info>$ cat foo.php | php %command.full_name% --diff -</info>
  105833. Finally, if you don't need BC kept on CLI level, you might use `PHP_CS_FIXER_FUTURE_MODE` to start using options that
  105834. would be default in next MAJOR release and to forbid using deprecated configuration:
  105835. <info>$ PHP_CS_FIXER_FUTURE_MODE=1 php %command.full_name% -v --diff</info>
  105836. Exit code
  105837. ---------
  105838. Exit code of the `%command.name%` command is built using following bit flags:
  105839. * 0 - OK.
  105840. * 1 - General error (or PHP minimal requirement not matched).
  105841. * 4 - Some files have invalid syntax (only in dry-run mode).
  105842. * 8 - Some files need fixing (only in dry-run mode).
  105843. * 16 - Configuration error of the application.
  105844. * 32 - Configuration error of a Fixer.
  105845. * 64 - Exception raised within the application.
  105846. EOF;
  105847. }
  105848. protected function configure(): void
  105849. {
  105850. $this->setDefinition(
  105851. [
  105852. new InputArgument('path', InputArgument::IS_ARRAY, 'The path(s) that rules will be run against (each path can be a file or directory).'),
  105853. new InputOption('path-mode', '', InputOption::VALUE_REQUIRED, 'Specify path mode (can be `override` or `intersection`).', ConfigurationResolver::PATH_MODE_OVERRIDE),
  105854. new InputOption('allow-risky', '', InputOption::VALUE_REQUIRED, 'Are risky fixers allowed (can be `yes` or `no`).'),
  105855. new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The path to a config file.'),
  105856. new InputOption('dry-run', '', InputOption::VALUE_NONE, 'Only shows which files would have been modified.'),
  105857. new InputOption('rules', '', InputOption::VALUE_REQUIRED, 'List of rules that should be run against configured paths.'),
  105858. new InputOption('using-cache', '', InputOption::VALUE_REQUIRED, 'Should cache be used (can be `yes` or `no`).'),
  105859. new InputOption('allow-unsupported-php-version', '', InputOption::VALUE_REQUIRED, 'Should the command refuse to run on unsupported PHP version (can be `yes` or `no`).'),
  105860. new InputOption('cache-file', '', InputOption::VALUE_REQUIRED, 'The path to the cache file.'),
  105861. new InputOption('diff', '', InputOption::VALUE_NONE, 'Prints diff for each file.'),
  105862. new InputOption('format', '', InputOption::VALUE_REQUIRED, 'To output results in other formats.'),
  105863. new InputOption('stop-on-violation', '', InputOption::VALUE_NONE, 'Stop execution on first violation.'),
  105864. new InputOption('show-progress', '', InputOption::VALUE_REQUIRED, 'Type of progress indicator (none, dots).'),
  105865. new InputOption('sequential', '', InputOption::VALUE_NONE, 'Enforce sequential analysis.'),
  105866. ]
  105867. );
  105868. }
  105869. protected function execute(InputInterface $input, OutputInterface $output): int
  105870. {
  105871. $verbosity = $output->getVerbosity();
  105872. $passedConfig = $input->getOption('config');
  105873. $passedRules = $input->getOption('rules');
  105874. if (null !== $passedConfig && null !== $passedRules) {
  105875. throw new InvalidConfigurationException('Passing both `--config` and `--rules` options is not allowed.');
  105876. }
  105877. $resolver = new ConfigurationResolver(
  105878. $this->defaultConfig,
  105879. [
  105880. 'allow-risky' => $input->getOption('allow-risky'),
  105881. 'config' => $passedConfig,
  105882. 'dry-run' => $this->isDryRun($input),
  105883. 'rules' => $passedRules,
  105884. 'path' => $input->getArgument('path'),
  105885. 'path-mode' => $input->getOption('path-mode'),
  105886. 'using-cache' => $input->getOption('using-cache'),
  105887. 'allow-unsupported-php-version' => $input->getOption('allow-unsupported-php-version'),
  105888. 'cache-file' => $input->getOption('cache-file'),
  105889. 'format' => $input->getOption('format'),
  105890. 'diff' => $input->getOption('diff'),
  105891. 'stop-on-violation' => $input->getOption('stop-on-violation'),
  105892. 'verbosity' => $verbosity,
  105893. 'show-progress' => $input->getOption('show-progress'),
  105894. 'sequential' => $input->getOption('sequential'),
  105895. ],
  105896. getcwd(),
  105897. $this->toolInfo
  105898. );
  105899. $reporter = $resolver->getReporter();
  105900. $stdErr = $output instanceof ConsoleOutputInterface
  105901. ? $output->getErrorOutput()
  105902. : ('txt' === $reporter->getFormat() ? $output : null);
  105903. if (null !== $stdErr) {
  105904. $stdErr->writeln(Application::getAboutWithRuntime(true));
  105905. if (version_compare(PHP_VERSION, ConfigInterface::PHP_VERSION_SYNTAX_SUPPORTED.'.99', '>')) {
  105906. $message = \sprintf(
  105907. 'PHP CS Fixer currently supports PHP syntax only up to PHP %s, current PHP version: %s.',
  105908. ConfigInterface::PHP_VERSION_SYNTAX_SUPPORTED,
  105909. PHP_VERSION
  105910. );
  105911. if (!$resolver->getUnsupportedPhpVersionAllowed()) {
  105912. $message .= ' Add Config::setUnsupportedPhpVersionAllowed(true) to allow executions on unsupported PHP versions. Such execution may be unstable and you may experience code modified in a wrong way.';
  105913. $stdErr->writeln(\sprintf(
  105914. $stdErr->isDecorated() ? '<bg=red;fg=white;>%s</>' : '%s',
  105915. $message
  105916. ));
  105917. return 1;
  105918. }
  105919. $message .= ' Execution may be unstable. You may experience code modified in a wrong way. Please report such cases at https://github.com/PHP-CS-Fixer/PHP-CS-Fixer. Remove Config::setUnsupportedPhpVersionAllowed(true) to allow executions only on supported PHP versions.';
  105920. $stdErr->writeln(\sprintf(
  105921. $stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s',
  105922. $message
  105923. ));
  105924. }
  105925. $isParallel = $resolver->getParallelConfig()->getMaxProcesses() > 1;
  105926. $stdErr->writeln(\sprintf(
  105927. 'Running analysis on %d core%s.',
  105928. $resolver->getParallelConfig()->getMaxProcesses(),
  105929. $isParallel ? \sprintf(
  105930. 's with %d file%s per process',
  105931. $resolver->getParallelConfig()->getFilesPerProcess(),
  105932. $resolver->getParallelConfig()->getFilesPerProcess() > 1 ? 's' : ''
  105933. ) : ' sequentially'
  105934. ));
  105935. $usageDocs = 'https://cs.symfony.com/doc/usage.html';
  105936. $stdErr->writeln(\sprintf(
  105937. $stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s',
  105938. $isParallel
  105939. ? 'Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!'
  105940. : \sprintf(
  105941. 'You can enable parallel runner and speed up the analysis! Please see %s for more information.',
  105942. $stdErr->isDecorated()
  105943. ? \sprintf('<href=%s;bg=yellow;fg=red;bold>usage docs</>', OutputFormatter::escape($usageDocs))
  105944. : $usageDocs
  105945. )
  105946. ));
  105947. $configFile = $resolver->getConfigFile();
  105948. $stdErr->writeln(\sprintf('Loaded config <comment>%s</comment>%s.', $resolver->getConfig()->getName(), null === $configFile ? '' : ' from "'.$configFile.'"'));
  105949. if ($resolver->getUsingCache()) {
  105950. $cacheFile = $resolver->getCacheFile();
  105951. if (is_file($cacheFile)) {
  105952. $stdErr->writeln(\sprintf('Using cache file "%s".', $cacheFile));
  105953. }
  105954. }
  105955. }
  105956. $finder = new \ArrayIterator(iterator_to_array($resolver->getFinder()));
  105957. if (null !== $stdErr && $resolver->configFinderIsOverridden()) {
  105958. $stdErr->writeln(
  105959. \sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', 'Paths from configuration file have been overridden by paths provided as command arguments.')
  105960. );
  105961. }
  105962. $progressType = $resolver->getProgressType();
  105963. $progressOutput = $this->progressOutputFactory->create(
  105964. $progressType,
  105965. new OutputContext(
  105966. $stdErr,
  105967. (new Terminal())->getWidth(),
  105968. \count($finder)
  105969. )
  105970. );
  105971. $runner = new Runner(
  105972. $finder,
  105973. $resolver->getFixers(),
  105974. $resolver->getDiffer(),
  105975. ProgressOutputType::NONE !== $progressType ? $this->eventDispatcher : null,
  105976. $this->errorsManager,
  105977. $resolver->getLinter(),
  105978. $resolver->isDryRun(),
  105979. $resolver->getCacheManager(),
  105980. $resolver->getDirectory(),
  105981. $resolver->shouldStopOnViolation(),
  105982. $resolver->getParallelConfig(),
  105983. $input,
  105984. $resolver->getConfigFile()
  105985. );
  105986. $this->eventDispatcher->addListener(FileProcessed::NAME, [$progressOutput, 'onFixerFileProcessed']);
  105987. $this->stopwatch->start('fixFiles');
  105988. $changed = $runner->fix();
  105989. $this->stopwatch->stop('fixFiles');
  105990. $this->eventDispatcher->removeListener(FileProcessed::NAME, [$progressOutput, 'onFixerFileProcessed']);
  105991. $progressOutput->printLegend();
  105992. $fixEvent = $this->stopwatch->getEvent('fixFiles');
  105993. $reportSummary = new ReportSummary(
  105994. $changed,
  105995. \count($finder),
  105996. $fixEvent->getDuration(),
  105997. $fixEvent->getMemory(),
  105998. OutputInterface::VERBOSITY_VERBOSE <= $verbosity,
  105999. $resolver->isDryRun(),
  106000. $output->isDecorated()
  106001. );
  106002. $output->isDecorated()
  106003. ? $output->write($reporter->generate($reportSummary))
  106004. : $output->write($reporter->generate($reportSummary), false, OutputInterface::OUTPUT_RAW);
  106005. $invalidErrors = $this->errorsManager->getInvalidErrors();
  106006. $exceptionErrors = $this->errorsManager->getExceptionErrors();
  106007. $lintErrors = $this->errorsManager->getLintErrors();
  106008. if (null !== $stdErr) {
  106009. $errorOutput = new ErrorOutput($stdErr);
  106010. if (\count($invalidErrors) > 0) {
  106011. $errorOutput->listErrors('linting before fixing', $invalidErrors);
  106012. }
  106013. if (\count($exceptionErrors) > 0) {
  106014. $errorOutput->listErrors('fixing', $exceptionErrors);
  106015. }
  106016. if (\count($lintErrors) > 0) {
  106017. $errorOutput->listErrors('linting after fixing', $lintErrors);
  106018. }
  106019. }
  106020. $exitStatusCalculator = new FixCommandExitStatusCalculator();
  106021. return $exitStatusCalculator->calculate(
  106022. $resolver->isDryRun(),
  106023. \count($changed) > 0,
  106024. \count($invalidErrors) > 0,
  106025. \count($exceptionErrors) > 0,
  106026. \count($lintErrors) > 0
  106027. );
  106028. }
  106029. protected function isDryRun(InputInterface $input): bool
  106030. {
  106031. return $input->getOption('dry-run');
  106032. }
  106033. }
  106034. <?php
  106035. declare(strict_types=1);
  106036. namespace PhpCsFixer\Console\Command;
  106037. use PhpCsFixer\Config;
  106038. use PhpCsFixer\ConfigInterface;
  106039. use PhpCsFixer\Console\ConfigurationResolver;
  106040. use PhpCsFixer\ToolInfoInterface;
  106041. use Symfony\Component\Console\Attribute\AsCommand;
  106042. use Symfony\Component\Console\Command\Command;
  106043. use Symfony\Component\Console\Input\InputInterface;
  106044. use Symfony\Component\Console\Input\InputOption;
  106045. use Symfony\Component\Console\Output\OutputInterface;
  106046. use Symfony\Component\Filesystem\Path;
  106047. #[AsCommand(name: 'list-files')]
  106048. final class ListFilesCommand extends Command
  106049. {
  106050. protected static $defaultName = 'list-files';
  106051. private ConfigInterface $defaultConfig;
  106052. private ToolInfoInterface $toolInfo;
  106053. public function __construct(ToolInfoInterface $toolInfo)
  106054. {
  106055. parent::__construct();
  106056. $this->defaultConfig = new Config();
  106057. $this->toolInfo = $toolInfo;
  106058. }
  106059. protected function configure(): void
  106060. {
  106061. $this
  106062. ->setDefinition(
  106063. [
  106064. new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The path to a .php-cs-fixer.php file.'),
  106065. ]
  106066. )
  106067. ->setDescription('List all files being fixed by the given config.')
  106068. ;
  106069. }
  106070. protected function execute(InputInterface $input, OutputInterface $output): int
  106071. {
  106072. $passedConfig = $input->getOption('config');
  106073. $cwd = getcwd();
  106074. $resolver = new ConfigurationResolver(
  106075. $this->defaultConfig,
  106076. [
  106077. 'config' => $passedConfig,
  106078. ],
  106079. $cwd,
  106080. $this->toolInfo
  106081. );
  106082. $finder = $resolver->getFinder();
  106083. foreach ($finder as $file) {
  106084. if ($file->isFile()) {
  106085. $relativePath = './'.Path::makeRelative($file->getRealPath(), $cwd);
  106086. $relativePath = str_replace('/', \DIRECTORY_SEPARATOR, $relativePath);
  106087. $output->writeln(escapeshellarg($relativePath));
  106088. }
  106089. }
  106090. return 0;
  106091. }
  106092. }
  106093. <?php
  106094. declare(strict_types=1);
  106095. namespace PhpCsFixer\Console\Command;
  106096. use Clue\React\NDJson\Decoder;
  106097. use Clue\React\NDJson\Encoder;
  106098. use PhpCsFixer\Cache\NullCacheManager;
  106099. use PhpCsFixer\Config;
  106100. use PhpCsFixer\Console\ConfigurationResolver;
  106101. use PhpCsFixer\Error\ErrorsManager;
  106102. use PhpCsFixer\Runner\Event\FileProcessed;
  106103. use PhpCsFixer\Runner\Parallel\ParallelAction;
  106104. use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
  106105. use PhpCsFixer\Runner\Parallel\ParallelisationException;
  106106. use PhpCsFixer\Runner\Runner;
  106107. use PhpCsFixer\ToolInfoInterface;
  106108. use React\EventLoop\StreamSelectLoop;
  106109. use React\Socket\ConnectionInterface;
  106110. use React\Socket\TcpConnector;
  106111. use Symfony\Component\Console\Attribute\AsCommand;
  106112. use Symfony\Component\Console\Command\Command;
  106113. use Symfony\Component\Console\Input\InputInterface;
  106114. use Symfony\Component\Console\Input\InputOption;
  106115. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  106116. use Symfony\Component\Console\Output\OutputInterface;
  106117. use Symfony\Component\EventDispatcher\EventDispatcher;
  106118. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  106119. #[AsCommand(name: 'worker', description: 'Internal command for running fixers in parallel', hidden: true)]
  106120. final class WorkerCommand extends Command
  106121. {
  106122. public const ERROR_PREFIX = 'WORKER_ERROR::';
  106123. protected static $defaultName = 'worker';
  106124. protected static $defaultDescription = 'Internal command for running fixers in parallel';
  106125. private ToolInfoInterface $toolInfo;
  106126. private ConfigurationResolver $configurationResolver;
  106127. private ErrorsManager $errorsManager;
  106128. private EventDispatcherInterface $eventDispatcher;
  106129. private array $events;
  106130. public function __construct(ToolInfoInterface $toolInfo)
  106131. {
  106132. parent::__construct();
  106133. $this->setHidden(true);
  106134. $this->toolInfo = $toolInfo;
  106135. $this->errorsManager = new ErrorsManager();
  106136. $this->eventDispatcher = new EventDispatcher();
  106137. }
  106138. protected function configure(): void
  106139. {
  106140. $this->setDefinition(
  106141. [
  106142. new InputOption('port', null, InputOption::VALUE_REQUIRED, 'Specifies parallelisation server\'s port.'),
  106143. new InputOption('identifier', null, InputOption::VALUE_REQUIRED, 'Specifies parallelisation process\' identifier.'),
  106144. new InputOption('allow-risky', '', InputOption::VALUE_REQUIRED, 'Are risky fixers allowed (can be `yes` or `no`).'),
  106145. new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The path to a config file.'),
  106146. new InputOption('dry-run', '', InputOption::VALUE_NONE, 'Only shows which files would have been modified.'),
  106147. new InputOption('rules', '', InputOption::VALUE_REQUIRED, 'List of rules that should be run against configured paths.'),
  106148. new InputOption('using-cache', '', InputOption::VALUE_REQUIRED, 'Should cache be used (can be `yes` or `no`).'),
  106149. new InputOption('cache-file', '', InputOption::VALUE_REQUIRED, 'The path to the cache file.'),
  106150. new InputOption('diff', '', InputOption::VALUE_NONE, 'Prints diff for each file.'),
  106151. new InputOption('stop-on-violation', '', InputOption::VALUE_NONE, 'Stop execution on first violation.'),
  106152. ]
  106153. );
  106154. }
  106155. protected function execute(InputInterface $input, OutputInterface $output): int
  106156. {
  106157. $errorOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
  106158. $identifier = $input->getOption('identifier');
  106159. $port = $input->getOption('port');
  106160. if (null === $identifier || !is_numeric($port)) {
  106161. throw new ParallelisationException('Missing parallelisation options');
  106162. }
  106163. try {
  106164. $runner = $this->createRunner($input);
  106165. } catch (\Throwable $e) {
  106166. throw new ParallelisationException('Unable to create runner: '.$e->getMessage(), 0, $e);
  106167. }
  106168. $loop = new StreamSelectLoop();
  106169. $tcpConnector = new TcpConnector($loop);
  106170. $tcpConnector
  106171. ->connect(\sprintf('127.0.0.1:%d', $port))
  106172. ->then(
  106173. function (ConnectionInterface $connection) use ($loop, $runner, $identifier): void {
  106174. $out = new Encoder($connection, JSON_INVALID_UTF8_IGNORE);
  106175. $in = new Decoder($connection, true, 512, JSON_INVALID_UTF8_IGNORE);
  106176. $out->write(['action' => ParallelAction::WORKER_HELLO, 'identifier' => $identifier]);
  106177. $handleError = static function (\Throwable $error) use ($out): void {
  106178. $out->write([
  106179. 'action' => ParallelAction::WORKER_ERROR_REPORT,
  106180. 'class' => \get_class($error),
  106181. 'message' => $error->getMessage(),
  106182. 'file' => $error->getFile(),
  106183. 'line' => $error->getLine(),
  106184. 'code' => $error->getCode(),
  106185. 'trace' => $error->getTraceAsString(),
  106186. ]);
  106187. };
  106188. $out->on('error', $handleError);
  106189. $in->on('error', $handleError);
  106190. $in->on('data', function (array $json) use ($loop, $runner, $out): void {
  106191. $action = $json['action'] ?? null;
  106192. if (ParallelAction::RUNNER_THANK_YOU === $action) {
  106193. $loop->stop();
  106194. return;
  106195. }
  106196. if (ParallelAction::RUNNER_REQUEST_ANALYSIS !== $action) {
  106197. throw new \LogicException(\sprintf('Unexpected action ParallelAction::%s.', $action));
  106198. }
  106199. $files = $json['files'];
  106200. foreach ($files as $path) {
  106201. $this->events = [];
  106202. $runner->setFileIterator(new \ArrayIterator([new \SplFileInfo($path)]));
  106203. $analysisResult = $runner->fix();
  106204. if (1 !== \count($this->events)) {
  106205. throw new ParallelisationException('Runner did not report a fixing event or reported too many.');
  106206. }
  106207. if (1 < \count($analysisResult)) {
  106208. throw new ParallelisationException('Runner returned more analysis results than expected.');
  106209. }
  106210. $out->write([
  106211. 'action' => ParallelAction::WORKER_RESULT,
  106212. 'file' => $path,
  106213. 'fileHash' => $this->events[0]->getFileHash(),
  106214. 'status' => $this->events[0]->getStatus(),
  106215. 'fixInfo' => array_pop($analysisResult),
  106216. 'errors' => $this->errorsManager->forPath($path),
  106217. ]);
  106218. }
  106219. $out->write(['action' => ParallelAction::WORKER_GET_FILE_CHUNK]);
  106220. });
  106221. },
  106222. static function (\Throwable $error) use ($errorOutput): void {
  106223. $errorOutput->writeln($error->getMessage());
  106224. }
  106225. )
  106226. ;
  106227. $loop->run();
  106228. return Command::SUCCESS;
  106229. }
  106230. private function createRunner(InputInterface $input): Runner
  106231. {
  106232. $passedConfig = $input->getOption('config');
  106233. $passedRules = $input->getOption('rules');
  106234. if (null !== $passedConfig && null !== $passedRules) {
  106235. throw new \RuntimeException('Passing both `--config` and `--rules` options is not allowed');
  106236. }
  106237. $this->eventDispatcher->addListener(FileProcessed::NAME, function (FileProcessed $event): void {
  106238. $this->events[] = $event;
  106239. });
  106240. $this->configurationResolver = new ConfigurationResolver(
  106241. new Config(),
  106242. [
  106243. 'allow-risky' => $input->getOption('allow-risky'),
  106244. 'config' => $passedConfig,
  106245. 'dry-run' => $input->getOption('dry-run'),
  106246. 'rules' => $passedRules,
  106247. 'path' => [],
  106248. 'path-mode' => ConfigurationResolver::PATH_MODE_OVERRIDE,
  106249. 'using-cache' => $input->getOption('using-cache'),
  106250. 'cache-file' => $input->getOption('cache-file'),
  106251. 'diff' => $input->getOption('diff'),
  106252. 'stop-on-violation' => $input->getOption('stop-on-violation'),
  106253. ],
  106254. getcwd(),
  106255. $this->toolInfo
  106256. );
  106257. return new Runner(
  106258. null,
  106259. $this->configurationResolver->getFixers(),
  106260. $this->configurationResolver->getDiffer(),
  106261. $this->eventDispatcher,
  106262. $this->errorsManager,
  106263. $this->configurationResolver->getLinter(),
  106264. $this->configurationResolver->isDryRun(),
  106265. new NullCacheManager(),
  106266. $this->configurationResolver->getDirectory(),
  106267. $this->configurationResolver->shouldStopOnViolation(),
  106268. ParallelConfigFactory::sequential(),
  106269. null,
  106270. $this->configurationResolver->getConfigFile()
  106271. );
  106272. }
  106273. }
  106274. <?php
  106275. declare(strict_types=1);
  106276. namespace PhpCsFixer\Console\Command;
  106277. use PhpCsFixer\Console\Application;
  106278. use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface;
  106279. use PhpCsFixer\PharCheckerInterface;
  106280. use PhpCsFixer\Preg;
  106281. use PhpCsFixer\ToolInfoInterface;
  106282. use Symfony\Component\Console\Attribute\AsCommand;
  106283. use Symfony\Component\Console\Command\Command;
  106284. use Symfony\Component\Console\Input\InputInterface;
  106285. use Symfony\Component\Console\Input\InputOption;
  106286. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  106287. use Symfony\Component\Console\Output\OutputInterface;
  106288. #[AsCommand(name: 'self-update')]
  106289. final class SelfUpdateCommand extends Command
  106290. {
  106291. protected static $defaultName = 'self-update';
  106292. private NewVersionCheckerInterface $versionChecker;
  106293. private ToolInfoInterface $toolInfo;
  106294. private PharCheckerInterface $pharChecker;
  106295. public function __construct(
  106296. NewVersionCheckerInterface $versionChecker,
  106297. ToolInfoInterface $toolInfo,
  106298. PharCheckerInterface $pharChecker
  106299. ) {
  106300. parent::__construct();
  106301. $this->versionChecker = $versionChecker;
  106302. $this->toolInfo = $toolInfo;
  106303. $this->pharChecker = $pharChecker;
  106304. }
  106305. protected function configure(): void
  106306. {
  106307. $this
  106308. ->setAliases(['selfupdate'])
  106309. ->setDefinition(
  106310. [
  106311. new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'),
  106312. ]
  106313. )
  106314. ->setDescription('Update php-cs-fixer.phar to the latest stable version.')
  106315. ->setHelp(
  106316. <<<'EOT'
  106317. The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
  106318. latest version released on:
  106319. <comment>https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases</comment>
  106320. <info>$ php php-cs-fixer.phar %command.name%</info>
  106321. EOT
  106322. )
  106323. ;
  106324. }
  106325. protected function execute(InputInterface $input, OutputInterface $output): int
  106326. {
  106327. if ($output instanceof ConsoleOutputInterface) {
  106328. $stdErr = $output->getErrorOutput();
  106329. $stdErr->writeln(Application::getAboutWithRuntime(true));
  106330. }
  106331. if (!$this->toolInfo->isInstalledAsPhar()) {
  106332. $output->writeln('<error>Self-update is available only for PHAR version.</error>');
  106333. return 1;
  106334. }
  106335. $currentVersion = $this->getApplication()->getVersion();
  106336. Preg::match('/^v?(?<major>\d+)\./', $currentVersion, $matches);
  106337. $currentMajor = (int) $matches['major'];
  106338. try {
  106339. $latestVersion = $this->versionChecker->getLatestVersion();
  106340. $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor);
  106341. } catch (\Exception $exception) {
  106342. $output->writeln(\sprintf(
  106343. '<error>Unable to determine newest version: %s</error>',
  106344. $exception->getMessage()
  106345. ));
  106346. return 1;
  106347. }
  106348. if (1 !== $this->versionChecker->compareVersions($latestVersion, $currentVersion)) {
  106349. $output->writeln('<info>PHP CS Fixer is already up-to-date.</info>');
  106350. return 0;
  106351. }
  106352. $remoteTag = $latestVersion;
  106353. if (
  106354. 0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion)
  106355. && true !== $input->getOption('force')
  106356. ) {
  106357. $output->writeln(\sprintf('<info>A new major version of PHP CS Fixer is available</info> (<comment>%s</comment>)', $latestVersion));
  106358. $output->writeln(\sprintf('<info>Before upgrading please read</info> https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/%s/UPGRADE-v%s.md', $latestVersion, $currentMajor + 1));
  106359. $output->writeln('<info>If you are ready to upgrade run this command with</info> <comment>-f</comment>');
  106360. $output->writeln('<info>Checking for new minor/patch version...</info>');
  106361. if (1 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $currentVersion)) {
  106362. $output->writeln('<info>No minor update for PHP CS Fixer.</info>');
  106363. return 0;
  106364. }
  106365. $remoteTag = $latestVersionOfCurrentMajor;
  106366. }
  106367. $localFilename = $_SERVER['argv'][0];
  106368. $realPath = realpath($localFilename);
  106369. if (false !== $realPath) {
  106370. $localFilename = $realPath;
  106371. }
  106372. if (!is_writable($localFilename)) {
  106373. $output->writeln(\sprintf('<error>No permission to update</error> "%s" <error>file.</error>', $localFilename));
  106374. return 1;
  106375. }
  106376. $tempFilename = \dirname($localFilename).'/'.basename($localFilename, '.phar').'-tmp.phar';
  106377. $remoteFilename = $this->toolInfo->getPharDownloadUri($remoteTag);
  106378. if (false === @copy($remoteFilename, $tempFilename)) {
  106379. $output->writeln(\sprintf('<error>Unable to download new version</error> %s <error>from the server.</error>', $remoteTag));
  106380. return 1;
  106381. }
  106382. chmod($tempFilename, 0777 & ~umask());
  106383. $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename);
  106384. if (null !== $pharInvalidityReason) {
  106385. unlink($tempFilename);
  106386. $output->writeln(\sprintf('<error>The download of</error> %s <error>is corrupt (%s).</error>', $remoteTag, $pharInvalidityReason));
  106387. $output->writeln('<error>Please re-run the "self-update" command to try again.</error>');
  106388. return 1;
  106389. }
  106390. rename($tempFilename, $localFilename);
  106391. $output->writeln(\sprintf('<info>PHP CS Fixer updated</info> (<comment>%s</comment> -> <comment>%s</comment>)', $currentVersion, $remoteTag));
  106392. return 0;
  106393. }
  106394. }
  106395. <?php
  106396. declare(strict_types=1);
  106397. namespace PhpCsFixer\Console\Command;
  106398. use PhpCsFixer\Documentation\DocumentationLocator;
  106399. use PhpCsFixer\Documentation\FixerDocumentGenerator;
  106400. use PhpCsFixer\Documentation\RuleSetDocumentationGenerator;
  106401. use PhpCsFixer\FixerFactory;
  106402. use PhpCsFixer\RuleSet\RuleSets;
  106403. use Symfony\Component\Console\Attribute\AsCommand;
  106404. use Symfony\Component\Console\Command\Command;
  106405. use Symfony\Component\Console\Input\InputInterface;
  106406. use Symfony\Component\Console\Output\OutputInterface;
  106407. use Symfony\Component\Filesystem\Filesystem;
  106408. use Symfony\Component\Finder\Finder;
  106409. use Symfony\Component\Finder\SplFileInfo;
  106410. #[AsCommand(name: 'documentation')]
  106411. final class DocumentationCommand extends Command
  106412. {
  106413. protected static $defaultName = 'documentation';
  106414. private Filesystem $filesystem;
  106415. public function __construct(Filesystem $filesystem)
  106416. {
  106417. parent::__construct();
  106418. $this->filesystem = $filesystem;
  106419. }
  106420. protected function configure(): void
  106421. {
  106422. $this
  106423. ->setAliases(['doc'])
  106424. ->setDescription('Dumps the documentation of the project into its "/doc" directory.')
  106425. ;
  106426. }
  106427. protected function execute(InputInterface $input, OutputInterface $output): int
  106428. {
  106429. $locator = new DocumentationLocator();
  106430. $fixerFactory = new FixerFactory();
  106431. $fixerFactory->registerBuiltInFixers();
  106432. $fixers = $fixerFactory->getFixers();
  106433. $setDefinitions = RuleSets::getSetDefinitions();
  106434. $fixerDocumentGenerator = new FixerDocumentGenerator($locator);
  106435. $ruleSetDocumentationGenerator = new RuleSetDocumentationGenerator($locator);
  106436. $docForFixerRelativePaths = [];
  106437. foreach ($fixers as $fixer) {
  106438. $docForFixerRelativePaths[] = $locator->getFixerDocumentationFileRelativePath($fixer);
  106439. $this->filesystem->dumpFile(
  106440. $locator->getFixerDocumentationFilePath($fixer),
  106441. $fixerDocumentGenerator->generateFixerDocumentation($fixer)
  106442. );
  106443. }
  106444. foreach (
  106445. (new Finder())->files()
  106446. ->in($locator->getFixersDocumentationDirectoryPath())
  106447. ->notPath($docForFixerRelativePaths) as $file
  106448. ) {
  106449. $this->filesystem->remove($file->getPathname());
  106450. }
  106451. $this->filesystem->dumpFile(
  106452. $locator->getFixersDocumentationIndexFilePath(),
  106453. $fixerDocumentGenerator->generateFixersDocumentationIndex($fixers)
  106454. );
  106455. foreach ((new Finder())->files()->in($locator->getRuleSetsDocumentationDirectoryPath()) as $file) {
  106456. $this->filesystem->remove($file->getPathname());
  106457. }
  106458. $paths = [];
  106459. foreach ($setDefinitions as $name => $definition) {
  106460. $path = $locator->getRuleSetsDocumentationFilePath($name);
  106461. $paths[$path] = $definition;
  106462. $this->filesystem->dumpFile($path, $ruleSetDocumentationGenerator->generateRuleSetsDocumentation($definition, $fixers));
  106463. }
  106464. $this->filesystem->dumpFile(
  106465. $locator->getRuleSetsDocumentationIndexFilePath(),
  106466. $ruleSetDocumentationGenerator->generateRuleSetsDocumentationIndex($paths)
  106467. );
  106468. $output->writeln('Docs updated.');
  106469. return 0;
  106470. }
  106471. }
  106472. <?php
  106473. declare(strict_types=1);
  106474. namespace PhpCsFixer\Console\Command;
  106475. use PhpCsFixer\ConfigurationException\InvalidConfigurationException;
  106476. use PhpCsFixer\Console\Report\ListSetsReport\ReporterFactory;
  106477. use PhpCsFixer\Console\Report\ListSetsReport\ReporterInterface;
  106478. use PhpCsFixer\Console\Report\ListSetsReport\ReportSummary;
  106479. use PhpCsFixer\Console\Report\ListSetsReport\TextReporter;
  106480. use PhpCsFixer\RuleSet\RuleSets;
  106481. use PhpCsFixer\Utils;
  106482. use Symfony\Component\Console\Attribute\AsCommand;
  106483. use Symfony\Component\Console\Command\Command;
  106484. use Symfony\Component\Console\Formatter\OutputFormatter;
  106485. use Symfony\Component\Console\Input\InputInterface;
  106486. use Symfony\Component\Console\Input\InputOption;
  106487. use Symfony\Component\Console\Output\OutputInterface;
  106488. #[AsCommand(name: 'list-sets')]
  106489. final class ListSetsCommand extends Command
  106490. {
  106491. protected static $defaultName = 'list-sets';
  106492. protected function configure(): void
  106493. {
  106494. $this
  106495. ->setDefinition(
  106496. [
  106497. new InputOption('format', '', InputOption::VALUE_REQUIRED, 'To output results in other formats.', (new TextReporter())->getFormat()),
  106498. ]
  106499. )
  106500. ->setDescription('List all available RuleSets.')
  106501. ;
  106502. }
  106503. protected function execute(InputInterface $input, OutputInterface $output): int
  106504. {
  106505. $reporter = $this->resolveReporterWithFactory(
  106506. $input->getOption('format'),
  106507. new ReporterFactory()
  106508. );
  106509. $reportSummary = new ReportSummary(
  106510. array_values(RuleSets::getSetDefinitions())
  106511. );
  106512. $report = $reporter->generate($reportSummary);
  106513. $output->isDecorated()
  106514. ? $output->write(OutputFormatter::escape($report))
  106515. : $output->write($report, false, OutputInterface::OUTPUT_RAW);
  106516. return 0;
  106517. }
  106518. private function resolveReporterWithFactory(string $format, ReporterFactory $factory): ReporterInterface
  106519. {
  106520. try {
  106521. $factory->registerBuiltInReporters();
  106522. $reporter = $factory->getReporter($format);
  106523. } catch (\UnexpectedValueException $e) {
  106524. $formats = $factory->getFormats();
  106525. sort($formats);
  106526. throw new InvalidConfigurationException(\sprintf('The format "%s" is not defined, supported are %s.', $format, Utils::naturalLanguageJoin($formats)));
  106527. }
  106528. return $reporter;
  106529. }
  106530. }
  106531. <?php
  106532. declare(strict_types=1);
  106533. namespace PhpCsFixer\Console\Command;
  106534. use PhpCsFixer\Config;
  106535. use PhpCsFixer\Console\Application;
  106536. use PhpCsFixer\Console\ConfigurationResolver;
  106537. use PhpCsFixer\Differ\DiffConsoleFormatter;
  106538. use PhpCsFixer\Differ\FullDiffer;
  106539. use PhpCsFixer\Documentation\FixerDocumentGenerator;
  106540. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  106541. use PhpCsFixer\Fixer\DeprecatedFixerInterface;
  106542. use PhpCsFixer\Fixer\ExperimentalFixerInterface;
  106543. use PhpCsFixer\Fixer\FixerInterface;
  106544. use PhpCsFixer\Fixer\InternalFixerInterface;
  106545. use PhpCsFixer\FixerConfiguration\AliasedFixerOption;
  106546. use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
  106547. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  106548. use PhpCsFixer\FixerDefinition\CodeSampleInterface;
  106549. use PhpCsFixer\FixerDefinition\FileSpecificCodeSampleInterface;
  106550. use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
  106551. use PhpCsFixer\FixerFactory;
  106552. use PhpCsFixer\Preg;
  106553. use PhpCsFixer\RuleSet\RuleSets;
  106554. use PhpCsFixer\StdinFileInfo;
  106555. use PhpCsFixer\Tokenizer\Tokens;
  106556. use PhpCsFixer\ToolInfo;
  106557. use PhpCsFixer\Utils;
  106558. use PhpCsFixer\WordMatcher;
  106559. use Symfony\Component\Console\Attribute\AsCommand;
  106560. use Symfony\Component\Console\Command\Command;
  106561. use Symfony\Component\Console\Formatter\OutputFormatter;
  106562. use Symfony\Component\Console\Input\InputArgument;
  106563. use Symfony\Component\Console\Input\InputInterface;
  106564. use Symfony\Component\Console\Input\InputOption;
  106565. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  106566. use Symfony\Component\Console\Output\OutputInterface;
  106567. #[AsCommand(name: 'describe')]
  106568. final class DescribeCommand extends Command
  106569. {
  106570. protected static $defaultName = 'describe';
  106571. private ?array $setNames = null;
  106572. private FixerFactory $fixerFactory;
  106573. private ?array $fixers = null;
  106574. public function __construct(?FixerFactory $fixerFactory = null)
  106575. {
  106576. parent::__construct();
  106577. if (null === $fixerFactory) {
  106578. $fixerFactory = new FixerFactory();
  106579. $fixerFactory->registerBuiltInFixers();
  106580. }
  106581. $this->fixerFactory = $fixerFactory;
  106582. }
  106583. protected function configure(): void
  106584. {
  106585. $this
  106586. ->setDefinition(
  106587. [
  106588. new InputArgument('name', InputArgument::REQUIRED, 'Name of rule / set.'),
  106589. new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The path to a .php-cs-fixer.php file.'),
  106590. ]
  106591. )
  106592. ->setDescription('Describe rule / ruleset.')
  106593. ;
  106594. }
  106595. protected function execute(InputInterface $input, OutputInterface $output): int
  106596. {
  106597. if ($output instanceof ConsoleOutputInterface) {
  106598. $stdErr = $output->getErrorOutput();
  106599. $stdErr->writeln(Application::getAboutWithRuntime(true));
  106600. }
  106601. $resolver = new ConfigurationResolver(
  106602. new Config(),
  106603. ['config' => $input->getOption('config')],
  106604. getcwd(),
  106605. new ToolInfo()
  106606. );
  106607. $this->fixerFactory->registerCustomFixers($resolver->getConfig()->getCustomFixers());
  106608. $name = $input->getArgument('name');
  106609. try {
  106610. if (str_starts_with($name, '@')) {
  106611. $this->describeSet($output, $name);
  106612. return 0;
  106613. }
  106614. $this->describeRule($output, $name);
  106615. } catch (DescribeNameNotFoundException $e) {
  106616. $matcher = new WordMatcher(
  106617. 'set' === $e->getType() ? $this->getSetNames() : array_keys($this->getFixers())
  106618. );
  106619. $alternative = $matcher->match($name);
  106620. $this->describeList($output, $e->getType());
  106621. throw new \InvalidArgumentException(\sprintf(
  106622. '%s "%s" not found.%s',
  106623. ucfirst($e->getType()),
  106624. $name,
  106625. null === $alternative ? '' : ' Did you mean "'.$alternative.'"?'
  106626. ));
  106627. }
  106628. return 0;
  106629. }
  106630. private function describeRule(OutputInterface $output, string $name): void
  106631. {
  106632. $fixers = $this->getFixers();
  106633. if (!isset($fixers[$name])) {
  106634. throw new DescribeNameNotFoundException($name, 'rule');
  106635. }
  106636. $fixer = $fixers[$name];
  106637. $definition = $fixer->getDefinition();
  106638. $output->writeln(\sprintf('<fg=blue>Description of the <info>`%s`</info> rule.</>', $name));
  106639. $output->writeln('');
  106640. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
  106641. $output->writeln(\sprintf('Fixer class: <comment>%s</comment>.', \get_class($fixer)));
  106642. $output->writeln('');
  106643. }
  106644. if ($fixer instanceof DeprecatedFixerInterface) {
  106645. $successors = $fixer->getSuccessorsNames();
  106646. $message = [] === $successors
  106647. ? \sprintf('it will be removed in version %d.0', Application::getMajorVersion() + 1)
  106648. : \sprintf('use %s instead', Utils::naturalLanguageJoinWithBackticks($successors));
  106649. $endMessage = '. '.ucfirst($message);
  106650. Utils::triggerDeprecation(new \RuntimeException(str_replace('`', '"', "Rule \"{$name}\" is deprecated{$endMessage}.")));
  106651. $message = Preg::replace('/(`[^`]+`)/', '<info>$1</info>', $message);
  106652. $output->writeln(\sprintf('<error>DEPRECATED</error>: %s.', $message));
  106653. $output->writeln('');
  106654. }
  106655. $output->writeln($definition->getSummary());
  106656. $description = $definition->getDescription();
  106657. if (null !== $description) {
  106658. $output->writeln($description);
  106659. }
  106660. $output->writeln('');
  106661. if ($fixer instanceof ExperimentalFixerInterface) {
  106662. $output->writeln('<error>Fixer applying this rule is EXPERIMENTAL.</error>.');
  106663. $output->writeln('It is not covered with backward compatibility promise and may produce unstable or unexpected results.');
  106664. $output->writeln('');
  106665. }
  106666. if ($fixer instanceof InternalFixerInterface) {
  106667. $output->writeln('<error>Fixer applying this rule is INTERNAL.</error>.');
  106668. $output->writeln('It is expected to be used only on PHP CS Fixer project itself.');
  106669. $output->writeln('');
  106670. }
  106671. if ($fixer->isRisky()) {
  106672. $output->writeln('<error>Fixer applying this rule is RISKY.</error>');
  106673. $riskyDescription = $definition->getRiskyDescription();
  106674. if (null !== $riskyDescription) {
  106675. $output->writeln($riskyDescription);
  106676. }
  106677. $output->writeln('');
  106678. }
  106679. if ($fixer instanceof ConfigurableFixerInterface) {
  106680. $configurationDefinition = $fixer->getConfigurationDefinition();
  106681. $options = $configurationDefinition->getOptions();
  106682. $output->writeln(\sprintf('Fixer is configurable using following option%s:', 1 === \count($options) ? '' : 's'));
  106683. foreach ($options as $option) {
  106684. $line = '* <info>'.OutputFormatter::escape($option->getName()).'</info>';
  106685. $allowed = HelpCommand::getDisplayableAllowedValues($option);
  106686. if (null === $allowed) {
  106687. $allowed = array_map(
  106688. static fn (string $type): string => '<comment>'.$type.'</comment>',
  106689. $option->getAllowedTypes(),
  106690. );
  106691. } else {
  106692. $allowed = array_map(static fn ($value): string => $value instanceof AllowedValueSubset
  106693. ? 'a subset of <comment>'.Utils::toString($value->getAllowedValues()).'</comment>'
  106694. : '<comment>'.Utils::toString($value).'</comment>', $allowed);
  106695. }
  106696. $line .= ' ('.Utils::naturalLanguageJoin($allowed, '').')';
  106697. $description = Preg::replace('/(`.+?`)/', '<info>$1</info>', OutputFormatter::escape($option->getDescription()));
  106698. $line .= ': '.lcfirst(Preg::replace('/\.$/', '', $description)).'; ';
  106699. if ($option->hasDefault()) {
  106700. $line .= \sprintf(
  106701. 'defaults to <comment>%s</comment>',
  106702. Utils::toString($option->getDefault())
  106703. );
  106704. } else {
  106705. $line .= '<comment>required</comment>';
  106706. }
  106707. if ($option instanceof DeprecatedFixerOption) {
  106708. $line .= '. <error>DEPRECATED</error>: '.Preg::replace(
  106709. '/(`.+?`)/',
  106710. '<info>$1</info>',
  106711. OutputFormatter::escape(lcfirst($option->getDeprecationMessage()))
  106712. );
  106713. }
  106714. if ($option instanceof AliasedFixerOption) {
  106715. $line .= '; <error>DEPRECATED</error> alias: <comment>'.$option->getAlias().'</comment>';
  106716. }
  106717. $output->writeln($line);
  106718. }
  106719. $output->writeln('');
  106720. }
  106721. $codeSamples = array_filter($definition->getCodeSamples(), static function (CodeSampleInterface $codeSample): bool {
  106722. if ($codeSample instanceof VersionSpecificCodeSampleInterface) {
  106723. return $codeSample->isSuitableFor(\PHP_VERSION_ID);
  106724. }
  106725. return true;
  106726. });
  106727. if (0 === \count($definition->getCodeSamples())) {
  106728. $output->writeln([
  106729. 'Fixing examples are not available for this rule.',
  106730. '',
  106731. ]);
  106732. } elseif (0 === \count($codeSamples)) {
  106733. $output->writeln([
  106734. 'Fixing examples <error>cannot be</error> demonstrated on the current PHP version.',
  106735. '',
  106736. ]);
  106737. } else {
  106738. $output->writeln('Fixing examples:');
  106739. $differ = new FullDiffer();
  106740. $diffFormatter = new DiffConsoleFormatter(
  106741. $output->isDecorated(),
  106742. \sprintf(
  106743. '<comment> ---------- begin diff ----------</comment>%s%%s%s<comment> ----------- end diff -----------</comment>',
  106744. PHP_EOL,
  106745. PHP_EOL
  106746. )
  106747. );
  106748. foreach ($codeSamples as $index => $codeSample) {
  106749. $old = $codeSample->getCode();
  106750. $tokens = Tokens::fromCode($old);
  106751. $configuration = $codeSample->getConfiguration();
  106752. if ($fixer instanceof ConfigurableFixerInterface) {
  106753. $fixer->configure($configuration ?? []);
  106754. }
  106755. $file = $codeSample instanceof FileSpecificCodeSampleInterface
  106756. ? $codeSample->getSplFileInfo()
  106757. : new StdinFileInfo();
  106758. $fixer->fix($file, $tokens);
  106759. $diff = $differ->diff($old, $tokens->generateCode());
  106760. if ($fixer instanceof ConfigurableFixerInterface) {
  106761. if (null === $configuration) {
  106762. $output->writeln(\sprintf(' * Example #%d. Fixing with the <comment>default</comment> configuration.', $index + 1));
  106763. } else {
  106764. $output->writeln(\sprintf(' * Example #%d. Fixing with configuration: <comment>%s</comment>.', $index + 1, Utils::toString($codeSample->getConfiguration())));
  106765. }
  106766. } else {
  106767. $output->writeln(\sprintf(' * Example #%d.', $index + 1));
  106768. }
  106769. $output->writeln([$diffFormatter->format($diff, ' %s'), '']);
  106770. }
  106771. }
  106772. $ruleSetConfigs = FixerDocumentGenerator::getSetsOfRule($name);
  106773. if ([] !== $ruleSetConfigs) {
  106774. ksort($ruleSetConfigs);
  106775. $plural = 1 !== \count($ruleSetConfigs) ? 's' : '';
  106776. $output->writeln("Fixer is part of the following rule set{$plural}:");
  106777. foreach ($ruleSetConfigs as $set => $config) {
  106778. if (null !== $config) {
  106779. $output->writeln(\sprintf('* <info>%s</info> with config: <comment>%s</comment>', $set, Utils::toString($config)));
  106780. } else {
  106781. $output->writeln(\sprintf('* <info>%s</info> with <comment>default</comment> config', $set));
  106782. }
  106783. }
  106784. $output->writeln('');
  106785. }
  106786. }
  106787. private function describeSet(OutputInterface $output, string $name): void
  106788. {
  106789. if (!\in_array($name, $this->getSetNames(), true)) {
  106790. throw new DescribeNameNotFoundException($name, 'set');
  106791. }
  106792. $ruleSetDefinitions = RuleSets::getSetDefinitions();
  106793. $fixers = $this->getFixers();
  106794. $output->writeln(\sprintf('<fg=blue>Description of the <info>`%s`</info> set.</>', $ruleSetDefinitions[$name]->getName()));
  106795. $output->writeln('');
  106796. $output->writeln($this->replaceRstLinks($ruleSetDefinitions[$name]->getDescription()));
  106797. $output->writeln('');
  106798. if ($ruleSetDefinitions[$name]->isRisky()) {
  106799. $output->writeln('<error>This set contains risky rules.</error>');
  106800. $output->writeln('');
  106801. }
  106802. $help = '';
  106803. foreach ($ruleSetDefinitions[$name]->getRules() as $rule => $config) {
  106804. if (str_starts_with($rule, '@')) {
  106805. $set = $ruleSetDefinitions[$rule];
  106806. $help .= \sprintf(
  106807. " * <info>%s</info>%s\n | %s\n\n",
  106808. $rule,
  106809. $set->isRisky() ? ' <error>risky</error>' : '',
  106810. $this->replaceRstLinks($set->getDescription())
  106811. );
  106812. continue;
  106813. }
  106814. $fixer = $fixers[$rule];
  106815. $definition = $fixer->getDefinition();
  106816. $help .= \sprintf(
  106817. " * <info>%s</info>%s\n | %s\n%s\n",
  106818. $rule,
  106819. $fixer->isRisky() ? ' <error>risky</error>' : '',
  106820. $definition->getSummary(),
  106821. true !== $config ? \sprintf(" <comment>| Configuration: %s</comment>\n", Utils::toString($config)) : ''
  106822. );
  106823. }
  106824. $output->write($help);
  106825. }
  106826. private function getFixers(): array
  106827. {
  106828. if (null !== $this->fixers) {
  106829. return $this->fixers;
  106830. }
  106831. $fixers = [];
  106832. foreach ($this->fixerFactory->getFixers() as $fixer) {
  106833. $fixers[$fixer->getName()] = $fixer;
  106834. }
  106835. $this->fixers = $fixers;
  106836. ksort($this->fixers);
  106837. return $this->fixers;
  106838. }
  106839. private function getSetNames(): array
  106840. {
  106841. if (null !== $this->setNames) {
  106842. return $this->setNames;
  106843. }
  106844. $this->setNames = RuleSets::getSetDefinitionNames();
  106845. return $this->setNames;
  106846. }
  106847. private function describeList(OutputInterface $output, string $type): void
  106848. {
  106849. if ($output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE) {
  106850. return;
  106851. }
  106852. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE || 'set' === $type) {
  106853. $output->writeln('<comment>Defined sets:</comment>');
  106854. $items = $this->getSetNames();
  106855. foreach ($items as $item) {
  106856. $output->writeln(\sprintf('* <info>%s</info>', $item));
  106857. }
  106858. }
  106859. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE || 'rule' === $type) {
  106860. $output->writeln('<comment>Defined rules:</comment>');
  106861. $items = array_keys($this->getFixers());
  106862. foreach ($items as $item) {
  106863. $output->writeln(\sprintf('* <info>%s</info>', $item));
  106864. }
  106865. }
  106866. }
  106867. private function replaceRstLinks(string $content): string
  106868. {
  106869. return Preg::replaceCallback(
  106870. '/(`[^<]+<[^>]+>`_)/',
  106871. static fn (array $matches) => Preg::replaceCallback(
  106872. '/`(.*)<(.*)>`_/',
  106873. static fn (array $matches): string => $matches[1].'('.$matches[2].')',
  106874. $matches[1]
  106875. ),
  106876. $content
  106877. );
  106878. }
  106879. }
  106880. <?php
  106881. declare(strict_types=1);
  106882. namespace PhpCsFixer;
  106883. final class FileRemoval
  106884. {
  106885. private array $files = [];
  106886. public function __construct()
  106887. {
  106888. register_shutdown_function([$this, 'clean']);
  106889. }
  106890. public function __destruct()
  106891. {
  106892. $this->clean();
  106893. }
  106894. public function __sleep(): array
  106895. {
  106896. throw new \BadMethodCallException('Cannot serialize '.self::class);
  106897. }
  106898. public function __wakeup(): void
  106899. {
  106900. throw new \BadMethodCallException('Cannot unserialize '.self::class);
  106901. }
  106902. public function observe(string $path): void
  106903. {
  106904. $this->files[$path] = true;
  106905. }
  106906. public function delete(string $path): void
  106907. {
  106908. if (isset($this->files[$path])) {
  106909. unset($this->files[$path]);
  106910. }
  106911. $this->unlink($path);
  106912. }
  106913. public function clean(): void
  106914. {
  106915. foreach ($this->files as $file => $value) {
  106916. $this->unlink($file);
  106917. }
  106918. $this->files = [];
  106919. }
  106920. private function unlink(string $path): void
  106921. {
  106922. @unlink($path);
  106923. }
  106924. }
  106925. <?php
  106926. declare(strict_types=1);
  106927. namespace PhpCsFixer;
  106928. interface PharCheckerInterface
  106929. {
  106930. public function checkFileValidity(string $filename): ?string;
  106931. }
  106932. Ÿ*¨NÙŒmý–k28`=B຋g3ý¨`SÍÄ´‹Ì(¶‰ä¯‰J/‘—£µ5KÆ‹J- ßNuÖ±[·yK���GBMB